Skip to content

Commit d6dcd70

Browse files
author
yaroslav8765
committed
fix: don't validate optional empty fields as invalid
1 parent f325691 commit d6dcd70

File tree

8 files changed

+188
-30
lines changed

8 files changed

+188
-30
lines changed

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
}

dev-demo/.env.sample

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
AWS_ACCESS_KEY_ID=
22
AWS_SECRET_ACCESS_KEY=
3-
ADMINFORTH_SECRET=123
4-
NODE_ENV=development
53
OPENAI_API_KEY=1
64
HEAVY_DEBUG=
7-
HEAVY_DEBUG_QUERY=
8-
PORT=3000
9-
10-
DATABASE_FILE=./db.sqlite
11-
DATABASE_FILE_URL=file:${DATABASE_FILE}
5+
HEAVY_DEBUG_QUERY=

dev-demo/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules
22
*.sqlite
3+
*.sqlite-journal
34
.env
45
db

dev-demo/custom/GroupTable.vue

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<template>
2+
<div class="p-4 space-y-4">
3+
4+
<JsonViewer
5+
:value="[
6+
{
7+
id: 1,
8+
name: 'Alice',
9+
meta: {
10+
age: 30,
11+
hobbies: ['reading', 'biking'],
12+
}
13+
},
14+
{
15+
id: 2,
16+
name: 'Bob',
17+
}
18+
]"
19+
:expandDepth="2"
20+
/>
21+
22+
23+
24+
25+
26+
27+
28+
<h3 class="text-lg font-semibold">Table with Pagination</h3>
29+
<p class="text-gray-600">This table demonstrates pagination with a custom page size.</p>
30+
31+
</div>
32+
33+
34+
35+
36+
37+
38+
39+
40+
41+
42+
<Table
43+
:columns="[
44+
{ label: 'Name', fieldName: 'name' },
45+
{ label: 'Age', fieldName: 'age' },
46+
{ label: 'Country', fieldName: 'country' },
47+
]"
48+
:data="[
49+
{ name: 'John', age: 30, country: 'US' },
50+
{ name: 'Rick', age: 25, country: 'CA' },
51+
{ name: 'Alice', age: 35, country: 'UK' },
52+
{ name: 'Colin', age: 40, country: 'AU' },
53+
]"
54+
:pageSize="2"
55+
></Table>
56+
57+
58+
<br>
59+
60+
61+
62+
<div class="flex bg-gray-50 border border-gray-300 rounded-lg focus:ring-blue-500
63+
focus:border-blue-500 w-full p-2.5 dark:bg-gray-700 dark:border-gray-600
64+
dark:focus:ring-blue-500 dark:focus:border-blue-500 relative max-w-full">
65+
66+
</div>
67+
68+
</template>
69+
70+
<script setup lang="ts">
71+
import { JsonViewer } from '@/afcl'
72+
import { Table } from '@/afcl'
73+
import { ref } from 'vue'
74+
75+
const currentValue = ref('');
76+
77+
async function complete(textBeforeCursor: string): Promise<string[]> {
78+
console.log('✋ complete request', textBeforeCursor);
79+
80+
// simulate delay
81+
await new Promise((resolve) => setTimeout(resolve, 400));
82+
83+
// generate N random words of M length
84+
const numOfWords = Math.floor(Math.random() * 7) + 1;
85+
const words = Array.from({ length: numOfWords }, () => Math.random().toString(36).substring(2, 15));
86+
87+
// if textBeforeCursor has "br" in end - insert \n in random word at random place
88+
if (textBeforeCursor.endsWith('br')) {
89+
const randomWordIndex = Math.floor(Math.random() * words.length);
90+
const pos = Math.floor(Math.random() * words[randomWordIndex].length);
91+
words[randomWordIndex] = words[randomWordIndex].substring(0, pos) + '\n' + words[randomWordIndex].substring(pos);
92+
}
93+
94+
return words.map((word) => `${word} `);
95+
}
96+
97+
// Фейковые данные
98+
const rows = [
99+
{
100+
id: 1,
101+
name: 'Alice',
102+
meta: {
103+
age: 30,
104+
}
105+
},
106+
{
107+
id: 2,
108+
name: 'Bob',
109+
meta: {
110+
age: 25,
111+
active: true,
112+
scores: { math: 92, english: 88 }
113+
}
114+
}
115+
]
116+
</script>

dev-demo/index.ts

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,14 @@ export const admin = new AdminForth({
7878
loginBackgroundImage: 'https://images.unsplash.com/photo-1534239697798-120952b76f2b?q=80&w=3389&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',
7979
loginBackgroundPosition: '1/2', // over, 3/4, 2/5, 3/5 (tailwind grid)
8080
demoCredentials: "adminforth:adminforth", // never use it for production
81-
loginPromptHTML: "Use email <b>adminforth</b> and password <b>adminforth</b> to login",
81+
// loginPromptHTML: async () => {
82+
// const adminforthUserExists = await admin.resource("users").count(Filters.EQ('email', 'adminforth')) > 0;
83+
// if (adminforthUserExists) {
84+
// return "Please use <b>adminforth</b> as username and <b>adminforth</b> as password"
85+
// }
86+
// return "";
87+
// },
88+
loginPromptHTML:"Nya without function",
8289
// loginBackgroundImage: '@@/pho.jpg',
8390
rememberMeDays: 30,
8491
beforeLoginConfirmation: [async ({adminUser, adminforth, extra}) => {
@@ -116,6 +123,29 @@ export const admin = new AdminForth({
116123
userMenu: '@@/login2.vue',
117124
// header: '@@/PropertyCost.vue',
118125
},
126+
customHeadItems: [
127+
{
128+
tagName: 'link',
129+
attributes: {
130+
rel: 'stylesheet',
131+
href: 'https://example.com/custom.css'
132+
}
133+
},
134+
{
135+
tagName: 'script',
136+
attributes: {
137+
src: 'https://example.com/custom.js',
138+
defer: true
139+
}
140+
},
141+
{
142+
tagName: 'meta',
143+
attributes: {
144+
name: 'theme-color',
145+
content: ' #000000'
146+
}
147+
}
148+
],
119149
customPages:[{
120150
path : '/login2',
121151
component: {
@@ -190,7 +220,7 @@ export const admin = new AdminForth({
190220
dataSources: [
191221
{
192222
id: 'maindb',
193-
url: process.env.DATABASE_URL,
223+
url: process.env.DATABASE_URL as string,
194224
},
195225
{
196226
id: 'pg',
@@ -202,7 +232,7 @@ export const admin = new AdminForth({
202232
},
203233
{
204234
id: 'ch',
205-
url: 'clickhouse://demo:demo@localhost:8125/demo',
235+
url: 'clickhouse://demo:demo@localhost:8124/demo',
206236
},
207237
{
208238
id: 'mysql',
@@ -225,6 +255,13 @@ export const admin = new AdminForth({
225255
translationsResource,
226256
],
227257
menu: [
258+
{
259+
label: 'TablesGroup',
260+
path: '/overview',
261+
homepage: true,
262+
icon: 'flowbite:chart-pie-solid',
263+
component: '@@/GroupTable.vue',
264+
},
228265
{
229266
label: 'Dashboard',
230267
icon: 'flowbite:chart-pie-solid',

dev-demo/package-lock.json

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dev-demo/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"author": "",
1616
"license": "ISC",
1717
"dependencies": {
18+
"@adminforth/foreign-inline-show": "^1.0.1",
1819
"@prisma/client": "^5.22.0",
1920
"better-sqlite3": "^10.1.0",
2021
"express": "^4.21.0",

dev-demo/resources/apartments.ts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import AdminForthAdapterLocal from "../../adapters/adminforth-storage-adapter-lo
2020
import AdminForthStorageAdapterLocalFilesystem from "../../adapters/adminforth-storage-adapter-local/index.js";
2121
import AdminForth from "../../adminforth";
2222
import { StorageAdapter } from "../../adminforth";
23-
23+
import ForeignInlineShowPlugin from '@adminforth/foreign-inline-show';
2424

2525
const demoChecker = async ({ record, adminUser, resource }) => {
2626
if (adminUser.dbUser.role !== "superadmin") {
@@ -143,7 +143,7 @@ export default {
143143
list: {
144144
file: "@/renderers/CountryFlag.vue",
145145
meta: {
146-
showCountryName: false,
146+
showCountryName: true,
147147
},
148148
},
149149
edit: {
@@ -245,8 +245,7 @@ export default {
245245
name: "square_meter",
246246
label: "Square",
247247
// allowMinMaxQuery: true,
248-
minValue: 1, // you can set min /max value for number fields
249-
maxValue: 100000000,
248+
minValue: 2, // you can set min /max value for number fields
250249
components: {
251250
list: {
252251
file: "@/renderers/HumanNumber.vue",
@@ -296,18 +295,6 @@ export default {
296295
showIn: {filter: true, show: true, edit: true, list: true, create: true},
297296
foreignResource: {
298297
resourceId: 'users',
299-
hooks: {
300-
dropdownList: {
301-
beforeDatasourceRequest: async ({ adminUser, query }: { adminUser: AdminUser, query: any }) => {
302-
if (adminUser.dbUser.role !== "superadmin") {
303-
query.filtersTools.replaceOrAddTopFilter(Filters.EQ("id", adminUser.dbUser.id));
304-
};
305-
return {
306-
"ok": true,
307-
};
308-
}
309-
},
310-
}
311298
}
312299
},
313300
{
@@ -331,8 +318,11 @@ export default {
331318
plugins: [
332319
...(process.env.AWS_ACCESS_KEY_ID
333320
? [
334-
new UploadPlugin({
335-
pathColumnName: "apartment_image",
321+
new ForeignInlineShowPlugin({
322+
foreignResourceId: 'adminuser',
323+
}),
324+
new UploadPlugin({
325+
pathColumnName: "apartment_image",
336326

337327
storageAdapter: new AdminForthAdapterS3Storage({
338328
region: "eu-central-1",

0 commit comments

Comments
 (0)