Skip to content

Commit 5bc3665

Browse files
committed
Merge branch 'next' of github.com:devforth/adminforth into next
2 parents 03e40a2 + 0347c5b commit 5bc3665

File tree

14 files changed

+115
-50
lines changed

14 files changed

+115
-50
lines changed

adminforth/auth.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,21 @@ class AdminForthAuth implements IAdminForthAuth {
8282
username: string,
8383
pk: string | null
8484
}) {
85+
console.log("in days", expireInDays);
8586
const expiresIn: string = expireInDays ? `${expireInDays}d` : (process.env.ADMINFORTH_AUTH_EXPIRESIN || '24h');
87+
console.log("in string", expiresIn);
8688
// might be h,m,d in string
89+
8790
const expiresInSec = parseTimeToSeconds(expiresIn);
8891

92+
console.log("expiresInSec", expiresInSec);
93+
8994
const token = this.issueJWT({ username, pk}, 'auth', expiresIn);
95+
console.log("token", token);
9096
const expiresCookieFormat = new Date(Date.now() + expiresInSec * 1000).toUTCString();
91-
97+
console.log("expiresCookieFormat", expiresCookieFormat);
9298
const brandSlug = this.adminforth.config.customization.brandNameSlug;
99+
console.log("brandSlug", brandSlug);
93100
response.setHeader('Set-Cookie', `adminforth_${brandSlug}_jwt=${token}; Path=${this.adminforth.config.baseUrl || '/'}; HttpOnly; SameSite=Strict; Expires=${expiresCookieFormat}`);
94101
}
95102

adminforth/dataConnectors/postgres.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,57 +97,62 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
9797
rows.forEach((row) => {
9898
const field: any = {};
9999
const baseType = row.type.toLowerCase();
100-
if (baseType == 'int') {
100+
const isPgArray = baseType.endsWith('[]');
101+
const normalizedBaseType = isPgArray ? baseType.slice(0, -2) : baseType;
102+
if (normalizedBaseType == 'int') {
101103
field.type = AdminForthDataTypes.INTEGER;
102104
field._underlineType = 'int';
103105

104-
} else if (baseType.includes('float') || baseType.includes('double')) {
106+
} else if (normalizedBaseType.includes('float') || normalizedBaseType.includes('double')) {
105107
field.type = AdminForthDataTypes.FLOAT;
106108
field._underlineType = 'float';
107109

108-
} else if (baseType.includes('bool')) {
110+
} else if (normalizedBaseType.includes('bool')) {
109111
field.type = AdminForthDataTypes.BOOLEAN;
110112
field._underlineType = 'bool';
111113

112-
} else if (baseType == 'uuid') {
114+
} else if (normalizedBaseType == 'uuid') {
113115
field.type = AdminForthDataTypes.STRING;
114116
field._underlineType = 'uuid';
115117

116-
} else if (baseType.includes('character varying')) {
118+
} else if (normalizedBaseType.includes('character varying')) {
117119
field.type = AdminForthDataTypes.STRING;
118120
field._underlineType = 'varchar';
119-
const length = baseType.match(/\d+/);
121+
const length = normalizedBaseType.match(/\d+/);
120122
field.maxLength = length ? parseInt(length[0]) : null;
121123

122-
} else if (baseType == 'text') {
124+
} else if (normalizedBaseType == 'text') {
123125
field.type = AdminForthDataTypes.TEXT;
124126
field._underlineType = 'text';
125127

126-
} else if (baseType.includes('decimal(') || baseType.includes('numeric(')) {
128+
} else if (normalizedBaseType.includes('decimal(') || normalizedBaseType.includes('numeric(')) {
127129
field.type = AdminForthDataTypes.DECIMAL;
128130
field._underlineType = 'decimal';
129-
const [precision, scale] = baseType.match(/\d+/g);
131+
const [precision, scale] = normalizedBaseType.match(/\d+/g);
130132
field.precision = parseInt(precision);
131133
field.scale = parseInt(scale);
132134

133-
} else if (baseType == 'real') {
135+
} else if (normalizedBaseType == 'real') {
134136
field.type = AdminForthDataTypes.FLOAT;
135137
field._underlineType = 'real';
136138

137-
} else if (baseType == 'date') {
139+
} else if (normalizedBaseType == 'date') {
138140
field.type = AdminForthDataTypes.DATE;
139141
field._underlineType = 'timestamp';
140142

141-
} else if (baseType.includes('date') || baseType.includes('time')) {
143+
} else if (normalizedBaseType.includes('date') || normalizedBaseType.includes('time')) {
142144
field.type = AdminForthDataTypes.DATETIME;
143145
field._underlineType = 'timestamp';
144-
} else if (baseType == 'json' || baseType == 'jsonb') {
146+
} else if (normalizedBaseType == 'json' || normalizedBaseType == 'jsonb') {
145147
field.type = AdminForthDataTypes.JSON;
146148
field._underlineType = 'json';
147149
} else {
148150
field.type = 'unknown'
149151
}
150152
field._baseTypeDebug = baseType;
153+
if (isPgArray) {
154+
field._isPgArray = true;
155+
}
151156
field.primaryKey = row.pk == 1;
152157
field.default = row.dflt_value;
153158
field.required = row.notnull && !row.dflt_value;
@@ -211,11 +216,22 @@ class PostgresConnector extends AdminForthBaseConnector implements IAdminForthDa
211216
} else if (field._underlineType == 'varchar') {
212217
return dayjs(value).toISOString();
213218
}
219+
} else if (field.isArray?.enabled) {
220+
if (value === null || value === undefined) {
221+
return null;
222+
}
223+
if (field._isPgArray) {
224+
return value;
225+
}
226+
if (field._underlineType == 'json') {
227+
return JSON.stringify(value);
228+
}
229+
return JSON.stringify(value);
214230
} else if (field.type == AdminForthDataTypes.BOOLEAN) {
215231
return value === null ? null : (value ? 1 : 0);
216232
} else if (field.type == AdminForthDataTypes.JSON) {
217233
if (field._underlineType == 'json') {
218-
return value;
234+
return typeof value === 'string' || value === null ? value : JSON.stringify(value);
219235
} else {
220236
return JSON.stringify(value);
221237
}

adminforth/documentation/docs/tutorial/03-Customization/15-afcl.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,10 +1967,10 @@ import { MixedChart } from '@/afcl'
19671967
</div>
19681968
</div>
19691969

1970-
## Json Viever
1970+
## Json Viewer
19711971

19721972
```ts
1973-
import { JsonViever } from '@/afcl'
1973+
import { JsonViewer } from '@/afcl'
19741974
```
19751975

19761976
### Basic

adminforth/documentation/docs/tutorial/07-Plugins/19-user-soft-delete.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,37 @@ import UserSoftDelete from "@adminforth/user-soft-delete";
4444
columns[
4545

4646
...
47-
47+
//diff-add
4848
{
49+
//diff-add
4950
name: "is_active",
51+
//diff-add
5052
type: AdminForthDataTypes.BOOLEAN,
53+
//diff-add
5154
label: "Is Active",
55+
//diff-add
5256
fillOnCreate: () => true,
57+
//diff-add
5358
filterOptions: {
59+
//diff-add
5460
multiselect: false,
61+
//diff-add
5562
},
63+
//diff-add
5664
showIn: {
65+
//diff-add
5766
list: true,
67+
//diff-add
5868
filter: true,
69+
//diff-add
5970
show: true,
71+
//diff-add
6072
create: false,
73+
//diff-add
6174
edit: true,
75+
//diff-add
6276
},
77+
//diff-add
6378
},
6479

6580
...
@@ -71,16 +86,25 @@ columns[
7186
plugins: [
7287

7388
...
74-
89+
//diff-add
7590
new UserSoftDelete({
91+
//diff-add
7692
activeFieldName: "is_active",
93+
//diff-add
7794
//in canDeactivate we pass a function, that specify adminusers roles, which can seactivate other adminusers
95+
//diff-add
7896
canDeactivate: async (adminUser: AdminUser) => {
97+
//diff-add
7998
if (adminUser.dbUser.role === "superadmin") {
99+
//diff-add
80100
return true;
101+
//diff-add
81102
}
103+
//diff-add
82104
return false;
105+
//diff-add
83106
}
107+
//diff-add
84108
}),
85109

86110
...

adminforth/modules/restApi.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,22 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
412412
if (menuItem.children) {
413413
menuItem.children.forEach(processItem);
414414
}
415+
if (menuItem.pageLabel) {
416+
translateRoutines.push(
417+
(async () => {
418+
menuItem.pageLabel = await tr(menuItem.pageLabel, `UserMenu.${menuItem.pageLabel}`);
419+
})()
420+
);
421+
}
415422
}
416423
newMenu.forEach((menuItem) => {
417424
processItem(menuItem);
418425
});
426+
if( this.adminforth.config.auth.userMenuSettingsPages) {
427+
this.adminforth.config.auth.userMenuSettingsPages.forEach((page) => {
428+
processItem(page);
429+
});
430+
}
419431
await Promise.all(translateRoutines);
420432

421433
// strip all backendOnly fields or not described in adminForth fields from dbUser
@@ -1341,7 +1353,7 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
13411353
}
13421354
}
13431355
}
1344-
1356+
13451357
const { error } = await this.adminforth.updateResourceRecord({ resource, record, adminUser, oldRecord, recordId, extra: { body, query, headers, cookies, requestUrl} });
13461358
if (error) {
13471359
return { error };

adminforth/spa/src/afcl/Tooltip.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
<teleport to="body" v-if="showTooltip">
66
<div
77
role="tooltip"
8-
class="absolute z-20 invisible inline-block px-3 py-2 text-sm font-medium text-lightTooltipText dark:darkTooltipText transition-opacity duration-300 bg-lightTooltipBackground rounded-lg shadow-sm opacity-0 tooltip dark:bg-darkTooltipBackground"
8+
class="absolute z-[100] invisible inline-block px-3 py-2 text-sm font-medium text-lightTooltipText dark:darkTooltipText transition-opacity duration-300 bg-lightTooltipBackground rounded-lg shadow-sm opacity-0 tooltip dark:bg-darkTooltipBackground"
99
ref="tooltip"
1010
>
1111
<slot name="tooltip"></slot>
12-
<div class="tooltip-arrow" data-popper-arrow></div>
12+
<div class="tooltip-arrow absolute -top-2" data-popper-arrow>
13+
<div class="absolute top-0 -left-0.5 w-0 h-0 border-l-8 border-r-8 border-b-8 border-l-transparent border-r-transparent border-b-lightTooltipBackground dark:border-b-darkTooltipBackground"></div>
14+
</div>
1315
</div>
1416
</teleport>
1517
</template>

adminforth/spa/src/components/AcceptModal.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<Teleport to="body">
3-
<div ref="modalEl" tabindex="-1" aria-hidden="true" class="hidden fixed inset-0 z-50 w-full h-full overflow-y-auto overflow-x-hidden flex items-center justify-center">
3+
<div ref="modalEl" tabindex="-1" aria-hidden="true" class="hidden fixed inset-0 z-[110] w-full h-full overflow-y-auto overflow-x-hidden flex items-center justify-center">
44
<div class="relative p-4 w-full max-w-md max-h-full" >
55
<div class="afcl-confirmation-container relative bg-lightAcceptModalBackground rounded-lg shadow dark:bg-darkAcceptModalBackground dark:shadow-black">
66
<button type="button" @click="modalStore.togleModal" class="absolute top-3 end-2.5 text-lightAcceptModalCloseIcon bg-transparent hover:bg-lightAcceptModalCloseIconHoverBackground hover:text-lightAcceptModalCloseIconHover rounded-lg text-sm w-8 h-8 ms-auto inline-flex justify-center items-center dark:text-darkAcceptModalCloseIcon dark:hover:bg-darkAcceptModalCloseIconHoverBackground dark:hover:text-darkAcceptModalCloseIconHover" >
@@ -51,6 +51,7 @@ onMounted(async () => {
5151
{
5252
closable: true,
5353
backdrop: 'static',
54+
backdropClasses: "bg-gray-900/50 dark:bg-gray-900/80 fixed inset-0 z-[100]"
5455
}
5556
);
5657
})

adminforth/spa/src/components/Toast.vue

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,22 @@
11
<template>
22

33

4-
<div class="afcl-toast flex items-center w-full p-4 rounded-lg shadow-lg dark:text-darkToastText dark:bg-darkToastBackground bg-lightToastBackground text-lightToastText"
4+
<div class="afcl-toast flex items-center w-full p-4 rounded-lg shadow-lg dark:text-darkToastText dark:bg-darkToastBackground bg-lightToastBackground text-lightToastText border-r-4"
5+
:class="toast.variant == 'info' ? 'border-lightPrimary dark:border-darkPrimary' : toast.variant == 'danger' ? 'border-red-500 dark:border-red-800' : toast.variant == 'warning' ? 'border-orange-500 dark:border-orange-700' : 'border-green-500 dark:border-green-800'"
56
role="alert"
67
>
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">
8-
<svg class="w-4 h-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 18 20">
9-
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.147 15.085a7.159 7.159 0 0 1-6.189 3.307A6.713 6.713 0 0 1 3.1 15.444c-2.679-4.513.287-8.737.888-9.548A4.373 4.373 0 0 0 5 1.608c1.287.953 6.445 3.218 5.537 10.5 1.5-1.122 2.706-3.01 2.853-6.14 1.433 1.049 3.993 5.395 1.757 9.117Z"/>
10-
</svg>
11-
<span class="sr-only">{{ $t('Fire icon') }}</span>
8+
<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-darkPrimary dark:!text-blue-100">
9+
<IconInfoCircleSolid class="w-5 h-5" aria-hidden="true" />
1210
</div>
1311
<div v-else-if="toast.variant == 'danger'" class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-red-500 bg-red-100 rounded-lg dark:bg-red-800 dark:text-red-200">
14-
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
15-
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 11.793a1 1 0 1 1-1.414 1.414L10 11.414l-2.293 2.293a1 1 0 0 1-1.414-1.414L8.586 10 6.293 7.707a1 1 0 0 1 1.414-1.414L10 8.586l2.293-2.293a1 1 0 0 1 1.414 1.414L11.414 10l2.293 2.293Z"/>
16-
</svg>
17-
<span class="sr-only">{{ $t('Error icon') }}</span>
12+
<IconCloseCircleSolid class="w-5 h-5" aria-hidden="true" />
1813
</div>
1914
<div v-else-if="toast.variant == 'warning'"class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-orange-500 bg-orange-100 rounded-lg dark:bg-orange-700 dark:text-orange-200">
20-
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
21-
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM10 15a1 1 0 1 1 0-2 1 1 0 0 1 0 2Zm1-4a1 1 0 0 1-2 0V6a1 1 0 0 1 2 0v5Z"/>
22-
</svg>
23-
<span class="sr-only">{{ $t('Warning icon') }}</span>
15+
<IconExclamationCircleSolid class="w-5 h-5" aria-hidden="true" />
16+
2417
</div>
2518
<div v-else class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-green-500 bg-green-100 rounded-lg dark:bg-green-800 dark:text-green-200">
26-
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
27-
<path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
28-
</svg>
29-
<span class="sr-only">{{ $t('Check icon') }}</span>
19+
<IconCheckCircleSolid class="w-5 h-5" aria-hidden="true" />
3020
</div>
3121

3222
<div class="ms-3 text-sm font-normal max-w-xs pr-2" v-if="toast.messageHtml" v-html="toast.messageHtml"></div>
@@ -47,6 +37,7 @@
4737
<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"/>
4838
</svg>
4939
</button>
40+
<!-- <div class="h-full ml-3 w-1 rounded-r-lg" :class="toast.variant == 'info' ? 'bg-lightPrimary dark:bg-darkPrimary' : toast.variant == 'danger' ? 'bg-red-500 dark:bg-red-800' : toast.variant == 'warning' ? 'bg-orange-500 dark:bg-orange-700' : 'bg-green-500 dark:bg-green-800'"></div> -->
5041
</div>
5142

5243

@@ -55,6 +46,8 @@
5546
<script setup lang="ts">
5647
import { onMounted } from 'vue';
5748
import { useToastStore } from '@/stores/toast';
49+
import { IconInfoCircleSolid, IconCloseCircleSolid, IconExclamationCircleSolid, IconCheckCircleSolid } from '@iconify-prerendered/vue-flowbite';
50+
5851
const toastStore = useToastStore();
5952
const emit = defineEmits(['close']);
6053
const props = defineProps<{

adminforth/spa/src/components/UserMenuSettingsButton.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
w-full select-none "
88
@click="showDropdown = !showDropdown"
99
>
10-
<span>Settings</span>
10+
<span>{{ $t('Settings') }}</span>
1111
<IconCaretDownSolid class="h-5 w-5 text-lightPrimary dark:text-gray-400 opacity-50 transition duration-150 ease-in"
1212
:class="{ 'transform rotate-180': showDropdown }"
1313
/>
@@ -40,9 +40,11 @@ import { computed, ref, onMounted, watch } from 'vue';
4040
import { useCoreStore } from '@/stores/core';
4141
import { getIcon } from '@/utils';
4242
import { useRouter } from 'vue-router';
43+
import { useI18n } from 'vue-i18n';
4344
4445
const router = useRouter();
4546
const coreStore = useCoreStore();
47+
const { t } = useI18n();
4648
4749
const showDropdown = ref(false);
4850
const props = defineProps(['meta', 'resource']);

adminforth/spa/src/stores/core.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const useCoreStore = defineStore('core', () => {
1616
const record: Ref<any | null> = ref({});
1717
const resource: Ref<AdminForthResourceCommon | null> = ref(null);
1818
const userData: Ref<UserData | null> = ref(null);
19+
const isResourceFetching = ref(false);
1920

2021
const resourceColumnsWithFilters = computed(() => {
2122
if (!resource.value) {
@@ -172,6 +173,7 @@ export const useCoreStore = defineStore('core', () => {
172173
// already fetched
173174
return;
174175
}
176+
isResourceFetching.value = true;
175177
resourceColumnsId.value = resourceId;
176178
resourceColumnsError.value = '';
177179
const res = await callAdminForthApi({
@@ -188,6 +190,7 @@ export const useCoreStore = defineStore('core', () => {
188190
resource.value = res.resource;
189191
resourceOptions.value = res.resource.options;
190192
}
193+
isResourceFetching.value = false;
191194
}
192195

193196
async function getPublicConfig() {
@@ -239,5 +242,6 @@ export const useCoreStore = defineStore('core', () => {
239242
fetchMenuBadges,
240243
resetAdminUser,
241244
resetResource,
245+
isResourceFetching,
242246
}
243247
})

0 commit comments

Comments
 (0)