Skip to content

Commit f1c91a0

Browse files
authored
Merge branch 'next' into AdminForth/735
2 parents cd38fd1 + 1ba495b commit f1c91a0

File tree

17 files changed

+108
-48
lines changed

17 files changed

+108
-48
lines changed

adminforth/dataConnectors/mongo.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
6969
return Number.isInteger(value) ? 'integer' : 'float';
7070
}
7171
if (value instanceof Date) return 'datetime';
72+
if (value && typeof value === 'object' && ('$numberDecimal' in value || value._bsontype === 'Decimal128')) return 'decimal';
7273
if (typeof value === 'object') return 'json';
7374
return 'string';
7475
}
@@ -89,13 +90,18 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
8990
sampleValues.set(fullKey, value);
9091
}
9192

92-
if (
93-
value instanceof Buffer ||
94-
(value && typeof value === 'object' && (value as any)._bsontype === 'Decimal128')
95-
) {
93+
if (value instanceof Buffer) {
9694
addType(fullKey, 'json');
9795
return;
9896
}
97+
if (
98+
value &&
99+
typeof value === 'object' &&
100+
('$numberDecimal' in value || (value as any)._bsontype === 'Decimal128')
101+
) {
102+
addType(fullKey, 'decimal');
103+
return;
104+
}
99105

100106
if (
101107
value &&
@@ -104,9 +110,10 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
104110
!(value instanceof Date)
105111
) {
106112
addType(fullKey, 'json');
107-
} else {
108-
addType(fullKey, detectType(value));
113+
return
109114
}
115+
116+
addType(fullKey, detectType(value));
110117
});
111118
}
112119

@@ -117,7 +124,7 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
117124
return Array.from(fieldTypes.entries()).map(([name, types]) => {
118125
const primaryKey = name === '_id';
119126

120-
const priority = ['datetime', 'date', 'integer', 'float', 'boolean', 'json', 'string'];
127+
const priority = ['datetime', 'date', 'integer', 'float', 'boolean', 'json', 'decimal', 'string'];
121128

122129
const matched = priority.find(t => types.has(t)) || 'string';
123130

@@ -129,8 +136,8 @@ class MongoConnector extends AdminForthBaseConnector implements IAdminForthDataS
129136
datetime: 'DATETIME',
130137
date: 'DATE',
131138
json: 'JSON',
139+
decimal: 'DECIMAL',
132140
};
133-
134141
return {
135142
name,
136143
type: typeMap[matched] ?? 'STRING',

adminforth/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,10 +315,10 @@ class AdminForth implements IAdminForth {
315315
return error;
316316
}
317317
} else {
318-
if (column.minValue !== undefined && record[column.name] < column.minValue) {
318+
if (column.minValue !== undefined && record[column.name] && record[column.name] < column.minValue) {
319319
return `Value in "${column.name}" must be greater than ${column.minValue}`;
320320
}
321-
if (column.maxValue !== undefined && record[column.name] > column.maxValue) {
321+
if (column.maxValue !== undefined && record[column.name] && record[column.name] > column.maxValue) {
322322
return `Value in "${column.name}" must be less than ${column.maxValue}`;
323323
}
324324
}

adminforth/modules/codeInjector.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -909,6 +909,9 @@ class CodeInjector implements ICodeInjector {
909909

910910
const command = 'run dev';
911911
console.log(`⚙️ spawn: npm ${command}...`);
912+
if (process.env.VITE_ADMINFORTH_PUBLIC_PATH) {
913+
console.log('⚠️ Your VITE_ADMINFORTH_PUBLIC_PATH:', process.env.VITE_ADMINFORTH_PUBLIC_PATH, 'has no effect');
914+
}
912915
const env = {
913916
VITE_ADMINFORTH_PUBLIC_PATH: this.adminforth.config.baseUrl,
914917
FORCE_COLOR: '1',

adminforth/modules/configValidator.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,14 @@ export default class ConfigValidator implements IConfigValidator {
853853
if (!newConfig.baseUrl) {
854854
newConfig.baseUrl = '';
855855
}
856+
857+
try {
858+
new URL(newConfig.baseUrl);
859+
errors.push(`⛔️ This url is absolute path: ${newConfig.baseUrl}, you have to use relative paths`);
860+
} catch {
861+
862+
}
863+
856864
if (!newConfig.baseUrl.endsWith('/')) {
857865
newConfig.baseUrlSlashed = `${newConfig.baseUrl}/`;
858866
} else {

adminforth/modules/restApi.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
215215
usernameFieldName: usernameColumn.label,
216216
loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
217217
loginBackgroundPosition: this.adminforth.config.auth.loginBackgroundPosition,
218+
removeBackgroundBlendMode: this.adminforth.config.auth.removeBackgroundBlendMode,
218219
title: this.adminforth.config.customization?.title,
219220
demoCredentials: this.adminforth.config.auth.demoCredentials,
220221
loginPromptHTML: await tr(this.adminforth.config.auth.loginPromptHTML, 'system.loginPromptHTML'),
@@ -298,6 +299,7 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
298299
usernameFieldName: usernameColumn.label,
299300
loginBackgroundImage: this.adminforth.config.auth.loginBackgroundImage,
300301
loginBackgroundPosition: this.adminforth.config.auth.loginBackgroundPosition,
302+
removeBackgroundBlendMode: this.adminforth.config.auth.removeBackgroundBlendMode,
301303
title: this.adminforth.config.customization?.title,
302304
demoCredentials: this.adminforth.config.auth.demoCredentials,
303305
loginPromptHTML: await tr(this.adminforth.config.auth.loginPromptHTML, 'system.loginPromptHTML'),

adminforth/spa/src/afcl/CountryFlag.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
<template>
2-
<component v-if="getFlagComponent(countryCode)" class="flag-icon rounded-sm" :is="getFlagComponent(countryCode)" />
2+
<div class="aspect-[4/3] w-8 h-6 flex items-center justify-center">
3+
<component v-if="getFlagComponent(countryCode)" :is="getFlagComponent(countryCode)" class="flag-icon w-full h-full object-contain rounded-sm"/>
34
<span v-else-if="countryCode">{{ countryCode }}</span>
5+
</div>
46
</template>
57

68
<script setup lang="ts">

adminforth/spa/src/afcl/Select.vue

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@
112112
</template>
113113

114114
<script setup lang="ts">
115-
import { ref, computed, onMounted, onUnmounted, watch, type Ref } from 'vue';
115+
import { ref, computed, onMounted, onUnmounted, watch, nextTick, type Ref } from 'vue';
116116
import { IconCaretDownSolid } from '@iconify-prerendered/vue-flowbite';
117117
import { useElementSize } from '@vueuse/core'
118118
@@ -177,14 +177,17 @@ function updateFromProps() {
177177
}
178178
}
179179
180-
function inputClick() {
180+
async function inputClick() {
181181
if (props.readonly) return;
182182
// Toggle local dropdown
183183
showDropdown.value = !showDropdown.value;
184184
// If the dropdown is about to close, reset the search
185185
if (!showDropdown.value && !search.value) {
186186
search.value = '';
187187
}
188+
189+
await nextTick();
190+
handleScroll();
188191
}
189192
190193
watch(

adminforth/spa/src/components/GroupsTable.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<template>
22
<div class="rounded-lg shadow-resourseFormShadow dark:shadow-darkResourseFormShadow dark:shadow-2xl">
3-
<div v-if="group.groupName && !group.noTitle" class="text-md font-semibold px-6 py-3 flex flex-1 items-center dark:border-gray-600 text-gray-700 bg-lightFormHeading dark:bg-gray-700 dark:text-gray-400 rounded-t-lg">
3+
<div v-if="group.groupName && !group.noTitle" class="text-md font-semibold px-6 py-3 flex flex-1 items-center dark:border-darkFormBorder text-gray-700 bg-lightFormHeading dark:bg-darkFormHeading dark:text-gray-400 rounded-t-lg">
44
{{ group.groupName }}
55
</div>
66
<table class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400">
7-
<thead v-if="!allColumnsHaveCustomComponent" class="text-xs text-gray-700 uppercase dark:text-gray-400 bg-lightFormHeading dark:bg-gray-700 block md:table-row-group ">
7+
<thead v-if="!allColumnsHaveCustomComponent" class="text-xs text-gray-700 uppercase dark:text-gray-400 bg-lightFormHeading dark:bg-darkFormHeading block md:table-row-group ">
88
<tr>
99
<th scope="col" :class="{'rounded-tl-lg': !group.groupName}" class="px-6 py-3 hidden md:w-52 md:table-cell">
1010
{{ $t('Field') }}
@@ -19,7 +19,7 @@
1919
v-for="(column, i) in group.columns"
2020
:key="column.name"
2121
v-if="currentValues !== null"
22-
class="bg-lightForm dark:bg-gray-800 dark:border-gray-700 block md:table-row"
22+
class="bg-lightForm dark:bg-darkForm dark:border-darkFormBorder block md:table-row"
2323
:class="{ 'border-b': i !== group.columns.length - 1}"
2424
>
2525
<td class="px-6 py-4 flex items-center block md:table-cell pb-0 md:pb-4"

adminforth/spa/src/components/ResourceListTable.vue

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,16 @@
1616
<!-- table header -->
1717
<tr class="t-header sticky z-10 top-0 text-xs bg-lightListTableHeading dark:bg-darkListTableHeading dark:text-gray-400">
1818
<td scope="col" class="p-4">
19-
<div class="flex items-center">
19+
<div class="flex items-center justify-center relative">
2020
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
2121
:disabled="!rows || !rows.length"
22-
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded
23-
focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
22+
class="peer appearance-none w-4 h-4 text-blue-600 bg-light-primary border border-gray-500 rounded-sm checked:bg-blue-500
23+
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
24+
focus:ring-2 dark:bg-dark-primary dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer">
2425
<label for="checkbox-all-search" class="sr-only">{{ $t('checkbox') }}</label>
26+
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
27+
<IconCheckOutline width="18" height="18" />
28+
</div>
2529
</div>
2630
</td>
2731

@@ -90,18 +94,27 @@
9094

9195
:class="{'border-b': rowI !== rows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
9296
>
93-
<td class="w-4 p-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
94-
<div class="flex items center ">
95-
<input
96-
@click="(e)=>{e.stopPropagation()}"
97-
id="checkbox-table-search-1"
98-
type="checkbox"
99-
:checked="checkboxesInternal.includes(row._primaryKeyValue)"
100-
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
101-
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 cursor-pointer">
102-
<label for="checkbox-table-search-1" class="sr-only">{{ $t('checkbox') }}</label>
97+
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
98+
<div class="flex items-center justify-center relative">
99+
<input
100+
@click="(e)=>e.stopPropagation()"
101+
id="checkbox-table-search-1"
102+
type="checkbox"
103+
:checked="checkboxesInternal.includes(row._primaryKeyValue)"
104+
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
105+
class="peer appearance-none w-4 h-4 text-blue-600 bg-light-primary border border-gray-500 rounded-sm checked:bg-blue-500
106+
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
107+
focus:ring-2 dark:bg-dark-primary dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer"
108+
/>
109+
<label for="checkbox-table-search-1" class="sr-only">
110+
{{ $t('checkbox') }}
111+
</label>
112+
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
113+
<IconCheckOutline width="18" height="18" />
103114
</div>
104-
</td>
115+
</div>
116+
</td>
117+
105118
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">
106119
<!-- if c.name in listComponentsPerColumn, render it. If not, render ValueRenderer -->
107120
<component
@@ -306,7 +319,8 @@ import {
306319
import {
307320
IconEyeSolid,
308321
IconPenSolid,
309-
IconTrashBinSolid
322+
IconTrashBinSolid,
323+
IconCheckOutline
310324
} from '@iconify-prerendered/vue-flowbite';
311325
import router from '@/router';
312326
import { Tooltip } from '@/afcl';

adminforth/spa/src/components/ResourceListTableVirtual.vue

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@
2020
<!-- table header -->
2121
<tr class="t-header sticky z-10 top-0 text-xs bg-lightListTableHeading dark:bg-darkListTableHeading dark:text-gray-400">
2222
<td scope="col" class="p-4">
23-
<div class="flex items-center">
23+
<div class="flex items-center justify-center relative">
2424
<input id="checkbox-all-search" type="checkbox" :checked="allFromThisPageChecked" @change="selectAll()"
2525
:disabled="!rows || !rows.length"
26-
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded
27-
focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600">
26+
class="peer appearance-none w-4 h-4 text-blue-600 bg-light-primary border border-gray-500 rounded-sm checked:bg-blue-500
27+
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
28+
focus:ring-2 dark:bg-dark-primary dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer">
2829
<label for="checkbox-all-search" class="sr-only">{{ $t('checkbox') }}</label>
30+
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
31+
<IconCheckOutline width="18" height="18" />
32+
</div>
2933
</div>
3034
</td>
3135

@@ -101,16 +105,24 @@
101105
:class="{'border-b': rowI !== visibleRows.length - 1, 'cursor-pointer': row._clickUrl !== null}"
102106
@mounted="(el) => updateRowHeight(`row_${row._primaryKeyValue}`, el.offsetHeight)"
103107
>
104-
<td class="w-4 p-4 cursor-default" @click="(e)=>{e.stopPropagation()}">
105-
<div class="flex items center ">
108+
<td class="w-4 p-4 cursor-default" @click="(e)=>e.stopPropagation()">
109+
<div class="flex items-center justify-center relative">
106110
<input
107-
@click="(e)=>{e.stopPropagation()}"
111+
@click="(e)=>e.stopPropagation()"
108112
id="checkbox-table-search-1"
109113
type="checkbox"
110114
:checked="checkboxesInternal.includes(row._primaryKeyValue)"
111115
@change="(e)=>{addToCheckedValues(row._primaryKeyValue)}"
112-
class="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 cursor-pointer">
113-
<label for="checkbox-table-search-1" class="sr-only">{{ $t('checkbox') }}</label>
116+
class="peer appearance-none w-4 h-4 text-blue-600 bg-gray-50 border border-gray-500 rounded-sm checked:bg-blue-500
117+
focus:ring-blue-600 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800
118+
focus:ring-2 dark:bg-gray-700 dark:border-gray-600 dark:checked:bg-blue-500 cursor-pointer"
119+
/>
120+
<label for="checkbox-table-search-1" class="sr-only">
121+
{{ $t('checkbox') }}
122+
</label>
123+
<div class="pointer-events-none absolute text-white text-[13px] leading-none peer-checked:block hidden">
124+
<IconCheckOutline width="18" height="18" />
125+
</div>
114126
</div>
115127
</td>
116128
<td v-for="c in columnsListed" class="px-2 md:px-3 lg:px-6 py-4">

0 commit comments

Comments
 (0)