nextjs-cms 0.0.1 → 0.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/LICENSE +21 -0
- package/README.md +289 -0
- package/dist/api/axios/axiosInstance.d.ts +2 -0
- package/dist/api/axios/axiosInstance.d.ts.map +1 -0
- package/dist/api/axios/axiosInstance.js +8 -0
- package/dist/api/index.d.ts +856 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +12 -0
- package/dist/api/lib/serverActions.d.ts +240 -0
- package/dist/api/lib/serverActions.d.ts.map +1 -0
- package/dist/api/lib/serverActions.js +834 -0
- package/dist/api/root.d.ts +829 -0
- package/dist/api/root.d.ts.map +1 -0
- package/dist/api/root.js +30 -0
- package/dist/api/routers/accountSettings.d.ts +61 -0
- package/dist/api/routers/accountSettings.d.ts.map +1 -0
- package/dist/api/routers/accountSettings.js +108 -0
- package/dist/api/routers/admins.d.ts +106 -0
- package/dist/api/routers/admins.d.ts.map +1 -0
- package/dist/api/routers/admins.js +219 -0
- package/dist/api/routers/auth.d.ts +48 -0
- package/dist/api/routers/auth.d.ts.map +1 -0
- package/dist/api/routers/auth.js +25 -0
- package/dist/api/routers/categorySection.d.ts +104 -0
- package/dist/api/routers/categorySection.d.ts.map +1 -0
- package/dist/api/routers/categorySection.js +38 -0
- package/dist/api/routers/cmsSettings.d.ts +49 -0
- package/dist/api/routers/cmsSettings.d.ts.map +1 -0
- package/dist/api/routers/cmsSettings.js +51 -0
- package/dist/api/routers/cpanel.d.ts +84 -0
- package/dist/api/routers/cpanel.d.ts.map +1 -0
- package/dist/api/routers/cpanel.js +216 -0
- package/dist/api/routers/files.d.ts +48 -0
- package/dist/api/routers/files.d.ts.map +1 -0
- package/dist/api/routers/files.js +23 -0
- package/dist/api/routers/gallery.d.ts +36 -0
- package/dist/api/routers/gallery.d.ts.map +1 -0
- package/dist/api/routers/gallery.js +62 -0
- package/dist/api/routers/googleAnalytics.d.ts +31 -0
- package/dist/api/routers/googleAnalytics.d.ts.map +1 -0
- package/dist/api/routers/googleAnalytics.js +7 -0
- package/dist/api/routers/hasItemsSection.d.ts +140 -0
- package/dist/api/routers/hasItemsSection.d.ts.map +1 -0
- package/dist/api/routers/hasItemsSection.js +34 -0
- package/dist/api/routers/navigation.d.ts +52 -0
- package/dist/api/routers/navigation.d.ts.map +1 -0
- package/dist/api/routers/navigation.js +11 -0
- package/dist/api/routers/simpleSection.d.ts +58 -0
- package/dist/api/routers/simpleSection.d.ts.map +1 -0
- package/dist/api/routers/simpleSection.js +12 -0
- package/dist/api/trpc.d.ts +107 -0
- package/dist/api/trpc.d.ts.map +1 -0
- package/dist/api/trpc.js +72 -0
- package/dist/auth/axios/axiosInstance.d.ts +2 -0
- package/dist/auth/axios/axiosInstance.d.ts.map +1 -0
- package/dist/auth/axios/axiosInstance.js +8 -0
- package/dist/auth/csrf.d.ts +30 -0
- package/dist/auth/csrf.d.ts.map +1 -0
- package/dist/auth/csrf.js +76 -0
- package/dist/auth/hooks/index.d.ts +4 -0
- package/dist/auth/hooks/index.d.ts.map +1 -0
- package/dist/auth/hooks/index.js +3 -0
- package/dist/auth/hooks/useAxiosPrivate.d.ts +5 -0
- package/dist/auth/hooks/useAxiosPrivate.d.ts.map +1 -0
- package/dist/auth/hooks/useAxiosPrivate.js +74 -0
- package/dist/auth/hooks/useRefreshToken.d.ts +7 -0
- package/dist/auth/hooks/useRefreshToken.d.ts.map +1 -0
- package/dist/auth/hooks/useRefreshToken.js +79 -0
- package/dist/auth/index.d.ts +23 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +44 -0
- package/dist/auth/jwt.d.ts +6 -0
- package/dist/auth/jwt.d.ts.map +1 -0
- package/dist/auth/jwt.js +25 -0
- package/dist/auth/lib/actions.d.ts +33 -0
- package/dist/auth/lib/actions.d.ts.map +1 -0
- package/dist/auth/lib/actions.js +209 -0
- package/dist/auth/lib/client.d.ts +4 -0
- package/dist/auth/lib/client.d.ts.map +1 -0
- package/dist/auth/lib/client.js +46 -0
- package/dist/auth/lib/index.d.ts +3 -0
- package/dist/auth/lib/index.d.ts.map +1 -0
- package/dist/auth/lib/index.js +2 -0
- package/dist/auth/react.d.ts +106 -0
- package/dist/auth/react.d.ts.map +1 -0
- package/dist/auth/react.js +347 -0
- package/dist/auth/trpc.d.ts +6 -0
- package/dist/auth/trpc.d.ts.map +1 -0
- package/dist/auth/trpc.js +81 -0
- package/dist/core/config/config-loader.d.ts +92 -0
- package/dist/core/config/config-loader.d.ts.map +1 -0
- package/dist/core/config/config-loader.js +230 -0
- package/dist/core/config/index.d.ts +3 -0
- package/dist/core/config/index.d.ts.map +1 -0
- package/dist/core/config/index.js +1 -0
- package/dist/core/config/loader.d.ts +2 -0
- package/dist/core/config/loader.d.ts.map +1 -0
- package/dist/core/config/loader.js +42 -0
- package/dist/core/db/index.d.ts +2 -0
- package/dist/core/db/index.d.ts.map +1 -0
- package/dist/core/db/index.js +1 -0
- package/dist/core/db/table-checker/DbTable.d.ts +6 -0
- package/dist/core/db/table-checker/DbTable.d.ts.map +1 -0
- package/dist/core/db/table-checker/DbTable.js +5 -0
- package/dist/core/db/table-checker/MysqlTable.d.ts +34 -0
- package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -0
- package/dist/core/db/table-checker/MysqlTable.js +102 -0
- package/dist/core/db/table-checker/index.d.ts +2 -0
- package/dist/core/db/table-checker/index.d.ts.map +1 -0
- package/dist/core/db/table-checker/index.js +1 -0
- package/dist/core/factories/FieldFactory.d.ts +124 -0
- package/dist/core/factories/FieldFactory.d.ts.map +1 -0
- package/dist/core/factories/FieldFactory.js +411 -0
- package/dist/core/factories/SectionFactory.d.ts +110 -0
- package/dist/core/factories/SectionFactory.d.ts.map +1 -0
- package/dist/core/factories/SectionFactory.js +415 -0
- package/dist/core/factories/index.d.ts +3 -0
- package/dist/core/factories/index.d.ts.map +1 -0
- package/dist/core/factories/index.js +2 -0
- package/dist/core/fields/checkbox.d.ts +63 -0
- package/dist/core/fields/checkbox.d.ts.map +1 -0
- package/dist/core/fields/checkbox.js +62 -0
- package/dist/core/fields/color.d.ts +84 -0
- package/dist/core/fields/color.d.ts.map +1 -0
- package/dist/core/fields/color.js +91 -0
- package/dist/core/fields/date.d.ts +100 -0
- package/dist/core/fields/date.d.ts.map +1 -0
- package/dist/core/fields/date.js +108 -0
- package/dist/core/fields/document.d.ts +180 -0
- package/dist/core/fields/document.d.ts.map +1 -0
- package/dist/core/fields/document.js +277 -0
- package/dist/core/fields/field-group.d.ts +18 -0
- package/dist/core/fields/field-group.d.ts.map +1 -0
- package/dist/core/fields/field-group.js +6 -0
- package/dist/core/fields/field.d.ts +126 -0
- package/dist/core/fields/field.d.ts.map +1 -0
- package/dist/core/fields/field.js +148 -0
- package/dist/core/fields/fileField.d.ts +15 -0
- package/dist/core/fields/fileField.d.ts.map +1 -0
- package/dist/core/fields/fileField.js +5 -0
- package/dist/core/fields/index.d.ts +65 -0
- package/dist/core/fields/index.d.ts.map +1 -0
- package/dist/core/fields/index.js +18 -0
- package/dist/core/fields/map.d.ts +167 -0
- package/dist/core/fields/map.d.ts.map +1 -0
- package/dist/core/fields/map.js +152 -0
- package/dist/core/fields/number.d.ts +186 -0
- package/dist/core/fields/number.d.ts.map +1 -0
- package/dist/core/fields/number.js +241 -0
- package/dist/core/fields/password.d.ts +109 -0
- package/dist/core/fields/password.d.ts.map +1 -0
- package/dist/core/fields/password.js +133 -0
- package/dist/core/fields/photo.d.ts +289 -0
- package/dist/core/fields/photo.d.ts.map +1 -0
- package/dist/core/fields/photo.js +410 -0
- package/dist/core/fields/richText.d.ts +295 -0
- package/dist/core/fields/richText.d.ts.map +1 -0
- package/dist/core/fields/richText.js +338 -0
- package/dist/core/fields/select.d.ts +366 -0
- package/dist/core/fields/select.d.ts.map +1 -0
- package/dist/core/fields/select.js +499 -0
- package/dist/core/fields/selectMultiple.d.ts +236 -0
- package/dist/core/fields/selectMultiple.d.ts.map +1 -0
- package/dist/core/fields/selectMultiple.js +417 -0
- package/dist/core/fields/tags.d.ts +131 -0
- package/dist/core/fields/tags.d.ts.map +1 -0
- package/dist/core/fields/tags.js +105 -0
- package/dist/core/fields/text.d.ts +136 -0
- package/dist/core/fields/text.d.ts.map +1 -0
- package/dist/core/fields/text.js +157 -0
- package/dist/core/fields/textArea.d.ts +107 -0
- package/dist/core/fields/textArea.d.ts.map +1 -0
- package/dist/core/fields/textArea.js +126 -0
- package/dist/core/fields/video.d.ts +148 -0
- package/dist/core/fields/video.d.ts.map +1 -0
- package/dist/core/fields/video.js +248 -0
- package/dist/core/helpers/entity.d.ts +8 -0
- package/dist/core/helpers/entity.d.ts.map +1 -0
- package/dist/core/helpers/entity.js +27 -0
- package/dist/core/helpers/index.d.ts +5 -0
- package/dist/core/helpers/index.d.ts.map +1 -0
- package/dist/core/helpers/index.js +3 -0
- package/dist/core/index.d.ts +8 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/sections/category.d.ts +283 -0
- package/dist/core/sections/category.d.ts.map +1 -0
- package/dist/core/sections/category.js +147 -0
- package/dist/core/sections/hasItems.d.ts +632 -0
- package/dist/core/sections/hasItems.d.ts.map +1 -0
- package/dist/core/sections/hasItems.js +144 -0
- package/dist/core/sections/index.d.ts +5 -0
- package/dist/core/sections/index.d.ts.map +1 -0
- package/dist/core/sections/index.js +4 -0
- package/dist/core/sections/section.d.ts +226 -0
- package/dist/core/sections/section.d.ts.map +1 -0
- package/dist/core/sections/section.js +341 -0
- package/dist/core/sections/simple.d.ts +99 -0
- package/dist/core/sections/simple.d.ts.map +1 -0
- package/dist/core/sections/simple.js +95 -0
- package/dist/core/security/dom.d.ts +11 -0
- package/dist/core/security/dom.d.ts.map +1 -0
- package/dist/core/security/dom.js +92 -0
- package/dist/core/submit/ItemEditSubmit.d.ts +76 -0
- package/dist/core/submit/ItemEditSubmit.d.ts.map +1 -0
- package/dist/core/submit/ItemEditSubmit.js +186 -0
- package/dist/core/submit/NewItemSubmit.d.ts +14 -0
- package/dist/core/submit/NewItemSubmit.d.ts.map +1 -0
- package/dist/core/submit/NewItemSubmit.js +93 -0
- package/dist/core/submit/SimpleSectionSubmit.d.ts +13 -0
- package/dist/core/submit/SimpleSectionSubmit.d.ts.map +1 -0
- package/dist/core/submit/SimpleSectionSubmit.js +93 -0
- package/dist/core/submit/index.d.ts +5 -0
- package/dist/core/submit/index.d.ts.map +1 -0
- package/dist/core/submit/index.js +4 -0
- package/dist/core/submit/submit.d.ts +116 -0
- package/dist/core/submit/submit.d.ts.map +1 -0
- package/dist/core/submit/submit.js +479 -0
- package/dist/core/types/index.d.ts +280 -0
- package/dist/core/types/index.d.ts.map +1 -0
- package/dist/core/types/index.js +1 -0
- package/dist/db/client.d.ts +9 -0
- package/dist/db/client.d.ts.map +1 -0
- package/dist/db/client.js +19 -0
- package/dist/db/config.d.ts +6 -0
- package/dist/db/config.d.ts.map +1 -0
- package/dist/db/config.js +22 -0
- package/dist/db/drizzle.config.d.ts +6 -0
- package/dist/db/drizzle.config.d.ts.map +1 -0
- package/dist/db/drizzle.config.js +18 -0
- package/dist/db/index.d.ts +3 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +3 -0
- package/dist/db/schema.d.ts +639 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +73 -0
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/translations/dictionaries/ar.json +279 -0
- package/dist/translations/dictionaries/en.json +279 -0
- package/dist/translations/index.d.ts +3 -0
- package/dist/translations/index.d.ts.map +1 -0
- package/dist/translations/index.js +15 -0
- package/dist/utils/CpanelApi.d.ts +25 -0
- package/dist/utils/CpanelApi.d.ts.map +1 -0
- package/dist/utils/CpanelApi.js +64 -0
- package/dist/utils/constants.d.ts +14 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +61 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/utils.d.ts +60 -0
- package/dist/utils/utils.d.ts.map +1 -0
- package/dist/utils/utils.js +132 -0
- package/dist/validators/checkbox.d.ts +4 -0
- package/dist/validators/checkbox.d.ts.map +1 -0
- package/dist/validators/checkbox.js +12 -0
- package/dist/validators/color.d.ts +4 -0
- package/dist/validators/color.d.ts.map +1 -0
- package/dist/validators/color.js +7 -0
- package/dist/validators/date.d.ts +4 -0
- package/dist/validators/date.d.ts.map +1 -0
- package/dist/validators/date.js +5 -0
- package/dist/validators/document.d.ts +4 -0
- package/dist/validators/document.d.ts.map +1 -0
- package/dist/validators/document.js +57 -0
- package/dist/validators/index.d.ts +15 -0
- package/dist/validators/index.d.ts.map +1 -0
- package/dist/validators/index.js +14 -0
- package/dist/validators/map.d.ts +4 -0
- package/dist/validators/map.d.ts.map +1 -0
- package/dist/validators/map.js +5 -0
- package/dist/validators/number.d.ts +4 -0
- package/dist/validators/number.d.ts.map +1 -0
- package/dist/validators/number.js +20 -0
- package/dist/validators/password.d.ts +4 -0
- package/dist/validators/password.d.ts.map +1 -0
- package/dist/validators/password.js +11 -0
- package/dist/validators/photo.d.ts +4 -0
- package/dist/validators/photo.d.ts.map +1 -0
- package/dist/validators/photo.js +100 -0
- package/dist/validators/richText.d.ts +4 -0
- package/dist/validators/richText.d.ts.map +1 -0
- package/dist/validators/richText.js +8 -0
- package/dist/validators/select-multiple.d.ts +10 -0
- package/dist/validators/select-multiple.d.ts.map +1 -0
- package/dist/validators/select-multiple.js +20 -0
- package/dist/validators/select.d.ts +4 -0
- package/dist/validators/select.d.ts.map +1 -0
- package/dist/validators/select.js +5 -0
- package/dist/validators/text.d.ts +4 -0
- package/dist/validators/text.d.ts.map +1 -0
- package/dist/validators/text.js +7 -0
- package/dist/validators/textarea.d.ts +4 -0
- package/dist/validators/textarea.d.ts.map +1 -0
- package/dist/validators/textarea.js +7 -0
- package/dist/validators/video.d.ts +4 -0
- package/dist/validators/video.d.ts.map +1 -0
- package/dist/validators/video.js +57 -0
- package/package.json +150 -6
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { baseFieldConfigSchema } from './field';
|
|
2
|
+
import { entityKind } from '../helpers';
|
|
3
|
+
import * as z from 'zod';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import { customAlphabet } from 'nanoid';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { FileField } from './fileField';
|
|
8
|
+
import { getCMSConfig } from '../config';
|
|
9
|
+
const maxFileSizeSchema = z.strictObject({
|
|
10
|
+
size: z.number().describe('Maximum file size'),
|
|
11
|
+
unit: z.enum(['kb', 'mb']).describe('Size unit'),
|
|
12
|
+
});
|
|
13
|
+
const configSchema = z.strictObject({
|
|
14
|
+
/**
|
|
15
|
+
* Maximum file size
|
|
16
|
+
* @example
|
|
17
|
+
* maxFileSize: {
|
|
18
|
+
* size: 512,
|
|
19
|
+
* unit: 'kb',
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
maxFileSize: maxFileSizeSchema.optional(),
|
|
23
|
+
/**
|
|
24
|
+
* Allowed document types
|
|
25
|
+
* @example
|
|
26
|
+
* type: ['pdf', 'doc', 'docx']
|
|
27
|
+
* @default ['pdf']
|
|
28
|
+
*/
|
|
29
|
+
type: z.array(z.enum(['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'])).optional(),
|
|
30
|
+
});
|
|
31
|
+
export class DocumentField extends FileField {
|
|
32
|
+
static [entityKind] = 'DocumentField';
|
|
33
|
+
maxFileSize;
|
|
34
|
+
mimeType;
|
|
35
|
+
extensions;
|
|
36
|
+
possibleExtensions = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'csv'];
|
|
37
|
+
/**
|
|
38
|
+
* _file is the file object if it's present
|
|
39
|
+
* Whereas the value is the path to the file
|
|
40
|
+
*/
|
|
41
|
+
_file;
|
|
42
|
+
_buffer;
|
|
43
|
+
_folder;
|
|
44
|
+
_allowedExtensions;
|
|
45
|
+
uploadsFolder = getCMSConfig().files.upload.uploadPath;
|
|
46
|
+
constructor(config, file) {
|
|
47
|
+
super(config, 'document');
|
|
48
|
+
if (file) {
|
|
49
|
+
this._file = file;
|
|
50
|
+
}
|
|
51
|
+
this.maxFileSize = config.maxFileSize ?? { size: 2, unit: 'mb' };
|
|
52
|
+
/**
|
|
53
|
+
* Check if the config type is valid
|
|
54
|
+
*/
|
|
55
|
+
if (config.type && config.type.some((type) => !this.possibleExtensions.includes(type))) {
|
|
56
|
+
throw new Error(`Invalid document type provided: ${config.type.join(', ')}, allowed types are: ${this.possibleExtensions.join(', ')}`);
|
|
57
|
+
}
|
|
58
|
+
this.extensions = config.type ?? ['pdf'];
|
|
59
|
+
/**
|
|
60
|
+
* Extract the mime types from the extensions
|
|
61
|
+
* @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
|
62
|
+
*/
|
|
63
|
+
this.mimeType = this.extensions.map((e) => {
|
|
64
|
+
switch (e) {
|
|
65
|
+
case 'pdf':
|
|
66
|
+
return 'application/pdf';
|
|
67
|
+
case 'doc':
|
|
68
|
+
return 'application/msword';
|
|
69
|
+
case 'docx':
|
|
70
|
+
return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
|
|
71
|
+
case 'xls':
|
|
72
|
+
return 'application/vnd.ms-excel';
|
|
73
|
+
case 'xlsx':
|
|
74
|
+
return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
|
|
75
|
+
case 'ppt':
|
|
76
|
+
return 'application/vnd.ms-powerpoint';
|
|
77
|
+
case 'pptx':
|
|
78
|
+
return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
|
|
79
|
+
case 'txt':
|
|
80
|
+
return 'text/plain';
|
|
81
|
+
case 'csv':
|
|
82
|
+
return 'text/csv';
|
|
83
|
+
default:
|
|
84
|
+
throw new Error(`Invalid image extension provided: ${e}`);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
/**
|
|
88
|
+
* Set the allowed extensions, add jpg if jpeg is present
|
|
89
|
+
*/
|
|
90
|
+
this._allowedExtensions = this.extensions;
|
|
91
|
+
}
|
|
92
|
+
exportForClient() {
|
|
93
|
+
return {
|
|
94
|
+
...super.exportForClient(),
|
|
95
|
+
maxFileSize: this.maxFileSize,
|
|
96
|
+
extensions: this._allowedExtensions,
|
|
97
|
+
mimeType: this.mimeType,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async readChunkFromFile({ arrayBuffer, length, startPosition = 0, }) {
|
|
101
|
+
return new Promise(async (resolve, reject) => {
|
|
102
|
+
try {
|
|
103
|
+
if (arrayBuffer) {
|
|
104
|
+
const buffer = new Uint8Array(arrayBuffer, startPosition, length);
|
|
105
|
+
resolve(buffer);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
reject(new Error('Error reading file'));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
reject(new Error('Error reading file'));
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write the file to the disk
|
|
118
|
+
*/
|
|
119
|
+
async writeToFile() {
|
|
120
|
+
if (!this._folder) {
|
|
121
|
+
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder by call postSubmit() before writing the file to disk`);
|
|
122
|
+
}
|
|
123
|
+
if (!this._buffer) {
|
|
124
|
+
throw new Error(`${this.label}: Buffer is not set. Make sure to call prepareForSubmission() before writing the file to disk`);
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
/**
|
|
128
|
+
* If .documents, and 'sectionName' folders don't exist, create them
|
|
129
|
+
*/
|
|
130
|
+
const documentsFolder = path.join(this.uploadsFolder, '.documents', this._folder);
|
|
131
|
+
if (!fs.existsSync(documentsFolder)) {
|
|
132
|
+
fs.mkdirSync(documentsFolder, { recursive: true });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Write the file to disk
|
|
136
|
+
*/
|
|
137
|
+
await fs.promises.writeFile(path.join(this.uploadsFolder, '.documents', this._folder, this.value), this._buffer);
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
throw new Error(`${this.label}: Error writing file to disk ${error.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async postSubmit(folder) {
|
|
144
|
+
if (!this._file)
|
|
145
|
+
return;
|
|
146
|
+
this._folder = folder;
|
|
147
|
+
await this.writeToFile();
|
|
148
|
+
}
|
|
149
|
+
async postSubmitRollback() {
|
|
150
|
+
if (!this._file)
|
|
151
|
+
return;
|
|
152
|
+
if (!this._folder) {
|
|
153
|
+
throw new Error(`${this.label}: Folder is not set. Make sure to set the folder before writing the file to disk`);
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
const pathToFile = path.join(this.uploadsFolder, '.documents', this._folder, this.value);
|
|
157
|
+
await fs.promises.unlink(pathToFile);
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
throw new Error(`${this.label}: Error deleting file from disk`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get the value of the field
|
|
165
|
+
*/
|
|
166
|
+
getValue() {
|
|
167
|
+
return this.value;
|
|
168
|
+
}
|
|
169
|
+
setFileName(value) {
|
|
170
|
+
this.value = value;
|
|
171
|
+
}
|
|
172
|
+
setValue(value) {
|
|
173
|
+
if (typeof value === 'string') {
|
|
174
|
+
this.setFileName(value);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
this.setFile(value);
|
|
178
|
+
}
|
|
179
|
+
setFile(file) {
|
|
180
|
+
if (!file || file.size === 0 || file.name?.trim() === '')
|
|
181
|
+
return;
|
|
182
|
+
this._file = file;
|
|
183
|
+
}
|
|
184
|
+
checkRequired() {
|
|
185
|
+
/**
|
|
186
|
+
* Check if the field is required
|
|
187
|
+
* If it is, check if the file is present
|
|
188
|
+
* If it's not, throw an error
|
|
189
|
+
* Note: Those values are coming from the browser (not safe)
|
|
190
|
+
*/
|
|
191
|
+
if (!this.required)
|
|
192
|
+
return;
|
|
193
|
+
if (!this._file || !this._file?.type || !this._file?.name || !this._file?.size) {
|
|
194
|
+
throw new Error(`Field ${this.label} is required`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Prepare the field for submission
|
|
199
|
+
*/
|
|
200
|
+
async prepareForSubmission() {
|
|
201
|
+
if (!this._file)
|
|
202
|
+
return;
|
|
203
|
+
/**
|
|
204
|
+
* Check the actual file size
|
|
205
|
+
*/
|
|
206
|
+
const arrayBuffer = await this._file.arrayBuffer();
|
|
207
|
+
this._buffer = Buffer.from(arrayBuffer);
|
|
208
|
+
if (!this._buffer.length) {
|
|
209
|
+
throw new Error(`Field ${this.label} is required`);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Check extension
|
|
213
|
+
*/
|
|
214
|
+
const ext = this._file.name.split('.').pop();
|
|
215
|
+
if (!ext || !this.extensions.includes(ext)) {
|
|
216
|
+
throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Read the first 4100 bytes of the file
|
|
220
|
+
*/
|
|
221
|
+
const chunkBuffer = await this.readChunkFromFile({ arrayBuffer, length: 4100 });
|
|
222
|
+
/**
|
|
223
|
+
* Get the file type from the buffer
|
|
224
|
+
*/
|
|
225
|
+
const { fileTypeFromBuffer } = await import('file-type');
|
|
226
|
+
const fileType = await fileTypeFromBuffer(chunkBuffer);
|
|
227
|
+
/**
|
|
228
|
+
* If the file type is invalid, return an error
|
|
229
|
+
*/
|
|
230
|
+
if (!fileType) {
|
|
231
|
+
throw new Error(`${this.label}: Invalid file type`);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Don't just trust the file extension
|
|
235
|
+
* Check the `fileType.ext` against the allowed extensions
|
|
236
|
+
*/
|
|
237
|
+
if (!fileType.ext || !this.extensions.includes(fileType.ext)) {
|
|
238
|
+
throw new Error(`${this.label}: Invalid file type or extension. Allowed extensions: ${this.extensions.join(', ')}`);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Generate a random name for the file
|
|
242
|
+
*/
|
|
243
|
+
this.value = customAlphabet('1234567890abcdef', 21)();
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
const optionsSchema = z.strictObject({
|
|
247
|
+
...baseFieldConfigSchema.shape,
|
|
248
|
+
...configSchema.shape,
|
|
249
|
+
});
|
|
250
|
+
const documentFieldConfigSchema = z.strictObject({
|
|
251
|
+
...optionsSchema.shape,
|
|
252
|
+
type: z.literal('document').describe('The type of the field'),
|
|
253
|
+
build: z.function().output(z.instanceof(DocumentField)).describe('Build a DocumentField instance from this config'),
|
|
254
|
+
});
|
|
255
|
+
/**
|
|
256
|
+
* Helper function to create a document field configuration
|
|
257
|
+
* Returns a config object with a build() method that can be serialized and used anywhere
|
|
258
|
+
* @param field
|
|
259
|
+
*/
|
|
260
|
+
export function documentField(field) {
|
|
261
|
+
/**
|
|
262
|
+
* Validate the field config
|
|
263
|
+
*/
|
|
264
|
+
const result = optionsSchema.safeParse(field);
|
|
265
|
+
if (!result.success) {
|
|
266
|
+
throw new Error(`[Field: ${field.name}]: ${z.prettifyError(result.error)}`);
|
|
267
|
+
}
|
|
268
|
+
const config = {
|
|
269
|
+
...field,
|
|
270
|
+
type: 'document',
|
|
271
|
+
build() {
|
|
272
|
+
// Use the original field config directly (it doesn't have build() method)
|
|
273
|
+
return new DocumentField(field);
|
|
274
|
+
},
|
|
275
|
+
};
|
|
276
|
+
return config;
|
|
277
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Field, FieldConfig } from '.';
|
|
2
|
+
import type { Prettify } from '../types';
|
|
3
|
+
export type FieldGroupOptions = {
|
|
4
|
+
title?: string;
|
|
5
|
+
order?: number;
|
|
6
|
+
fields: FieldConfig[];
|
|
7
|
+
};
|
|
8
|
+
export type FieldGroupConfig = Prettify<FieldGroupOptions> & {
|
|
9
|
+
type: 'field_group';
|
|
10
|
+
};
|
|
11
|
+
export type FieldGroup = {
|
|
12
|
+
id: number;
|
|
13
|
+
title?: string;
|
|
14
|
+
order?: number;
|
|
15
|
+
fields: Field[];
|
|
16
|
+
};
|
|
17
|
+
export declare function fieldGroup(group: FieldGroupOptions): FieldGroupConfig;
|
|
18
|
+
//# sourceMappingURL=field-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-group.d.ts","sourceRoot":"","sources":["../../../src/core/fields/field-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,GAAG,CAAA;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,MAAM,MAAM,iBAAiB,GAAG;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,WAAW,EAAE,CAAA;CACxB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,iBAAiB,CAAC,GAAG;IACzD,IAAI,EAAE,aAAa,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACrB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,KAAK,EAAE,CAAA;CAClB,CAAA;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,CAKrE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { entityKind } from '../helpers';
|
|
2
|
+
import type { ConditionalField, ConditionalRule, FieldType } from '../types';
|
|
3
|
+
import * as z from 'zod';
|
|
4
|
+
/**
|
|
5
|
+
* The Field class is used in the submit class to handle submission of the field
|
|
6
|
+
* It might also be used in the field factory to create the field in the form?
|
|
7
|
+
*/
|
|
8
|
+
export declare abstract class Field<TType extends FieldType = FieldType, TExtraFieldConfig extends object = object> implements AnyField<TType> {
|
|
9
|
+
static readonly [entityKind]: string;
|
|
10
|
+
readonly type: TType;
|
|
11
|
+
readonly name: string;
|
|
12
|
+
readonly label: string;
|
|
13
|
+
readonly required: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The default value of the field in the DB table,
|
|
16
|
+
*/
|
|
17
|
+
readonly defaultValue: any;
|
|
18
|
+
readonly order: number | undefined;
|
|
19
|
+
readonly groupId: number | undefined;
|
|
20
|
+
readonly conditionalRules: ConditionalRule[] | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* adminGenerated is used to determine if the field is generated by the admin or not.
|
|
23
|
+
* If set to false, the field will not be included in the form.
|
|
24
|
+
* If set to 'readonly', the field will be visible in the form as a `readonly` text, but will not be included in the submission.
|
|
25
|
+
*/
|
|
26
|
+
adminGenerated?: true | false | 'readonly';
|
|
27
|
+
/**
|
|
28
|
+
* Destination tables are used to save the value of the field in a different table.
|
|
29
|
+
* This is useful when we have a select multiple field, or a tags field and we want to save the values in a different table.
|
|
30
|
+
*
|
|
31
|
+
* Destination tables store only two identifier fields per row:
|
|
32
|
+
* - The reference item identifier: The identifier of the item that has this field as a field
|
|
33
|
+
* - The option identifier: The identifier of the select multiple or tags fields
|
|
34
|
+
*
|
|
35
|
+
* Destination tables have no identifier field.
|
|
36
|
+
* The primary key is automatically set as the combination of the reference item identifier and the option identifier.
|
|
37
|
+
*/
|
|
38
|
+
readonly destinationDb?: {
|
|
39
|
+
table: string;
|
|
40
|
+
itemIdentifier: string;
|
|
41
|
+
selectIdentifier: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Dynamically generated fields based on the value of `conditionalRules` from conditional fields.
|
|
45
|
+
*/
|
|
46
|
+
conditionalFields: ConditionalField[];
|
|
47
|
+
value: any;
|
|
48
|
+
constructor(config: BaseFieldConfig<TExtraFieldConfig>, fieldType: TType);
|
|
49
|
+
abstract checkRequired(): void;
|
|
50
|
+
setValue(value: any): void;
|
|
51
|
+
/**
|
|
52
|
+
* Perform any action after submitting the form
|
|
53
|
+
*/
|
|
54
|
+
postSubmit(variable?: any): Promise<void>;
|
|
55
|
+
postSubmitRollback(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Get the value of the field
|
|
58
|
+
*/
|
|
59
|
+
abstract getValue(): any;
|
|
60
|
+
getSubmitValue(): any;
|
|
61
|
+
/**
|
|
62
|
+
* Build the field to be used in a form
|
|
63
|
+
*/
|
|
64
|
+
build(): Promise<void>;
|
|
65
|
+
abstract prepareForSubmission(): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Generate a human-readable label from a field name.
|
|
68
|
+
* This is a static method to avoid recreation on every call.
|
|
69
|
+
*/
|
|
70
|
+
static generateLabel(name: string): string;
|
|
71
|
+
exportForClient(): {
|
|
72
|
+
type: TType;
|
|
73
|
+
name: string;
|
|
74
|
+
label: string;
|
|
75
|
+
required: boolean;
|
|
76
|
+
conditionalFields: ConditionalField[];
|
|
77
|
+
readonly: boolean;
|
|
78
|
+
defaultValue: any;
|
|
79
|
+
value: any;
|
|
80
|
+
};
|
|
81
|
+
hasSqlNameAndValue(): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Check if field is conditional
|
|
84
|
+
*/
|
|
85
|
+
isConditional(): boolean;
|
|
86
|
+
}
|
|
87
|
+
export type FieldClientConfig = ReturnType<Field['exportForClient']>;
|
|
88
|
+
export declare const conditionalRuleSchema: z.ZodCustom<ConditionalRule, ConditionalRule>;
|
|
89
|
+
/**
|
|
90
|
+
* Base field configuration schema
|
|
91
|
+
* This schema defines the base properties that all fields share
|
|
92
|
+
* Field types should extend this schema with their specific config
|
|
93
|
+
*/
|
|
94
|
+
export declare const baseFieldConfigSchema: z.ZodObject<{
|
|
95
|
+
name: z.ZodString;
|
|
96
|
+
label: z.ZodOptional<z.ZodString>;
|
|
97
|
+
required: z.ZodOptional<z.ZodBoolean>;
|
|
98
|
+
defaultValue: z.ZodOptional<z.ZodAny>;
|
|
99
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
100
|
+
/**
|
|
101
|
+
* Set if the field is only visible when all conditions are met.
|
|
102
|
+
* For now, conditionalRules only support one condition rule.
|
|
103
|
+
* If the condition is met, the field will be visible.
|
|
104
|
+
*/
|
|
105
|
+
conditionalRules: z.ZodOptional<z.ZodArray<z.ZodCustom<ConditionalRule, ConditionalRule>>>;
|
|
106
|
+
/**
|
|
107
|
+
* adminGenerated is used to determine if the field is generated by the admin or not.
|
|
108
|
+
* If set to false, the field will not be included in the form.
|
|
109
|
+
* If set to 'readonly', the field will be visible in the form as a `readonly` text, but will not be included in the submission.
|
|
110
|
+
*/
|
|
111
|
+
adminGenerated: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<true>, z.ZodLiteral<false>, z.ZodLiteral<"readonly">]>>;
|
|
112
|
+
}, z.core.$strict>;
|
|
113
|
+
/**
|
|
114
|
+
* This is the base field configuration
|
|
115
|
+
* It's used to define the base properties of a field
|
|
116
|
+
* It can be extended by other field types to add more properties
|
|
117
|
+
*/
|
|
118
|
+
export type BaseFieldConfig<TExtraFieldConfig extends object = object> = z.infer<typeof baseFieldConfigSchema> & TExtraFieldConfig;
|
|
119
|
+
/**
|
|
120
|
+
* This type represents the base field
|
|
121
|
+
*/
|
|
122
|
+
interface AnyField<TType extends FieldType> extends BaseFieldConfig<{}> {
|
|
123
|
+
type: TType;
|
|
124
|
+
}
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../../src/core/fields/field.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AACvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AAC5E,OAAO,KAAK,CAAC,MAAM,KAAK,CAAA;AAExB;;;GAGG;AACH,8BAAsB,KAAK,CAEvB,KAAK,SAAS,SAAS,GAAG,SAAS,EACnC,iBAAiB,SAAS,MAAM,GAAG,MAAM,CAC3C,YAAW,QAAQ,CAAC,KAAK,CAAC;IAExB,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,MAAM,CAAU;IAC9C,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAA;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAA;IAC1B;;OAEG;IACH,QAAQ,CAAC,YAAY,EAAE,GAAG,CAAA;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,gBAAgB,EAAE,eAAe,EAAE,GAAG,SAAS,CAAA;IAExD;;;;OAIG;IACH,cAAc,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,UAAU,CAAA;IAE1C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACrB,KAAK,EAAE,MAAM,CAAA;QACb,cAAc,EAAE,MAAM,CAAA;QACtB,gBAAgB,EAAE,MAAM,CAAA;KAC3B,CAAA;IAED;;OAEG;IACI,iBAAiB,EAAE,gBAAgB,EAAE,CAAK;IACnC,KAAK,EAAE,GAAG,CAAA;gBAKZ,MAAM,EAAE,eAAe,CAAC,iBAAiB,CAAC,EAAE,SAAS,EAAE,KAAK;IAYxE,QAAQ,CAAC,aAAa,IAAI,IAAI;IAE9B,QAAQ,CAAC,KAAK,EAAE,GAAG;IAInB;;OAEG;IACU,UAAU,CAAC,QAAQ,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhD;;OAEG;IACH,QAAQ,CAAC,QAAQ,IAAI,GAAG;IAExB,cAAc,IAAI,GAAG;IAIrB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,QAAQ,CAAC,oBAAoB,IAAI,OAAO,CAAC,IAAI,CAAC;IAE9C;;;OAGG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IAY1C,eAAe;;;;;;;;;;IAaf,kBAAkB,IAAI,OAAO;IAI7B;;OAEG;IACH,aAAa,IAAI,OAAO;CAa3B;AAED,MAAM,MAAM,iBAAiB,GAAG,UAAU,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAA;AAGpE,eAAO,MAAM,qBAAqB,+CAA8B,CAAA;AAEhE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;;;;;;IAM9B;;;;OAIG;;IAEH;;;;OAIG;;kBAEL,CAAA;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,CAAC,iBAAiB,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,GAC1G,iBAAiB,CAAA;AAErB;;GAEG;AACH,UAAU,QAAQ,CAAC,KAAK,SAAS,SAAS,CAAE,SAAQ,eAAe,CAAC,EAAE,CAAC;IACnE,IAAI,EAAE,KAAK,CAAA;CACd"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { entityKind } from '../helpers';
|
|
2
|
+
import * as z from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* The Field class is used in the submit class to handle submission of the field
|
|
5
|
+
* It might also be used in the field factory to create the field in the form?
|
|
6
|
+
*/
|
|
7
|
+
export class Field {
|
|
8
|
+
static [entityKind] = 'Field';
|
|
9
|
+
type;
|
|
10
|
+
name;
|
|
11
|
+
label;
|
|
12
|
+
required;
|
|
13
|
+
/**
|
|
14
|
+
* The default value of the field in the DB table,
|
|
15
|
+
*/
|
|
16
|
+
defaultValue;
|
|
17
|
+
order;
|
|
18
|
+
groupId;
|
|
19
|
+
conditionalRules;
|
|
20
|
+
/**
|
|
21
|
+
* adminGenerated is used to determine if the field is generated by the admin or not.
|
|
22
|
+
* If set to false, the field will not be included in the form.
|
|
23
|
+
* If set to 'readonly', the field will be visible in the form as a `readonly` text, but will not be included in the submission.
|
|
24
|
+
*/
|
|
25
|
+
adminGenerated;
|
|
26
|
+
/**
|
|
27
|
+
* Destination tables are used to save the value of the field in a different table.
|
|
28
|
+
* This is useful when we have a select multiple field, or a tags field and we want to save the values in a different table.
|
|
29
|
+
*
|
|
30
|
+
* Destination tables store only two identifier fields per row:
|
|
31
|
+
* - The reference item identifier: The identifier of the item that has this field as a field
|
|
32
|
+
* - The option identifier: The identifier of the select multiple or tags fields
|
|
33
|
+
*
|
|
34
|
+
* Destination tables have no identifier field.
|
|
35
|
+
* The primary key is automatically set as the combination of the reference item identifier and the option identifier.
|
|
36
|
+
*/
|
|
37
|
+
destinationDb;
|
|
38
|
+
/**
|
|
39
|
+
* Dynamically generated fields based on the value of `conditionalRules` from conditional fields.
|
|
40
|
+
*/
|
|
41
|
+
conditionalFields = [];
|
|
42
|
+
/*protected*/ value;
|
|
43
|
+
// No need to access the config
|
|
44
|
+
// protected config: BaseFieldConfig<TExtraFieldConfig>
|
|
45
|
+
constructor(config, fieldType) {
|
|
46
|
+
this.type = fieldType;
|
|
47
|
+
this.name = config.name;
|
|
48
|
+
this.label = config.label ?? Field.generateLabel(config.name);
|
|
49
|
+
this.required = config.required ?? false;
|
|
50
|
+
this.defaultValue = config.defaultValue;
|
|
51
|
+
this.order = config.order;
|
|
52
|
+
this.conditionalRules = config.conditionalRules;
|
|
53
|
+
this.adminGenerated = config.adminGenerated ?? true;
|
|
54
|
+
this.value = undefined;
|
|
55
|
+
}
|
|
56
|
+
setValue(value) {
|
|
57
|
+
this.value = value;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Perform any action after submitting the form
|
|
61
|
+
*/
|
|
62
|
+
async postSubmit(variable) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
async postSubmitRollback() {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
getSubmitValue() {
|
|
69
|
+
return this.getValue();
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build the field to be used in a form
|
|
73
|
+
*/
|
|
74
|
+
async build() {
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Generate a human-readable label from a field name.
|
|
79
|
+
* This is a static method to avoid recreation on every call.
|
|
80
|
+
*/
|
|
81
|
+
static generateLabel(name) {
|
|
82
|
+
return (name
|
|
83
|
+
// Replace underscores with spaces
|
|
84
|
+
.replace(/_/g, ' ')
|
|
85
|
+
// Insert space before camelCase capitals
|
|
86
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1 $2')
|
|
87
|
+
// Capitalize first letter of each word
|
|
88
|
+
.replace(/\b\w/g, (char) => char.toUpperCase()));
|
|
89
|
+
}
|
|
90
|
+
exportForClient() {
|
|
91
|
+
return {
|
|
92
|
+
type: this.type,
|
|
93
|
+
name: this.name,
|
|
94
|
+
label: this.label,
|
|
95
|
+
required: this.required,
|
|
96
|
+
conditionalFields: this.conditionalFields,
|
|
97
|
+
readonly: this.adminGenerated === 'readonly',
|
|
98
|
+
defaultValue: this.defaultValue,
|
|
99
|
+
value: this.value,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
hasSqlNameAndValue() {
|
|
103
|
+
return this.adminGenerated === true;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if field is conditional
|
|
107
|
+
*/
|
|
108
|
+
isConditional() {
|
|
109
|
+
let status = true;
|
|
110
|
+
if (this.conditionalRules && this.conditionalRules.length > 0) {
|
|
111
|
+
this.conditionalRules.map((rule) => {
|
|
112
|
+
if (!rule.field || !rule.value || !rule.condition) {
|
|
113
|
+
return (status = false);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
status = false;
|
|
119
|
+
}
|
|
120
|
+
return status;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Schema for ConditionalRule (circular dependency with FieldConfig, so use custom)
|
|
124
|
+
export const conditionalRuleSchema = z.custom();
|
|
125
|
+
/**
|
|
126
|
+
* Base field configuration schema
|
|
127
|
+
* This schema defines the base properties that all fields share
|
|
128
|
+
* Field types should extend this schema with their specific config
|
|
129
|
+
*/
|
|
130
|
+
export const baseFieldConfigSchema = z.strictObject({
|
|
131
|
+
name: z.string().describe('The name of the field'),
|
|
132
|
+
label: z.string().optional().describe('The label of the field'),
|
|
133
|
+
required: z.boolean().optional().describe('Whether the field is required'),
|
|
134
|
+
defaultValue: z.any().optional().describe('The default value of the field'),
|
|
135
|
+
order: z.number().optional().describe('The order of the field'),
|
|
136
|
+
/**
|
|
137
|
+
* Set if the field is only visible when all conditions are met.
|
|
138
|
+
* For now, conditionalRules only support one condition rule.
|
|
139
|
+
* If the condition is met, the field will be visible.
|
|
140
|
+
*/
|
|
141
|
+
conditionalRules: z.array(conditionalRuleSchema).optional().describe('Conditional rules for the field'),
|
|
142
|
+
/**
|
|
143
|
+
* adminGenerated is used to determine if the field is generated by the admin or not.
|
|
144
|
+
* If set to false, the field will not be included in the form.
|
|
145
|
+
* If set to 'readonly', the field will be visible in the form as a `readonly` text, but will not be included in the submission.
|
|
146
|
+
*/
|
|
147
|
+
adminGenerated: z.union([z.literal(true), z.literal(false), z.literal('readonly')]).optional(),
|
|
148
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Field } from './field';
|
|
2
|
+
import { entityKind } from '../helpers';
|
|
3
|
+
type FileType = 'photo' | 'video' | 'document';
|
|
4
|
+
export declare abstract class FileField<TType extends FileType = FileType, TExtraFieldConfig extends object = object> extends Field<TType, TExtraFieldConfig> {
|
|
5
|
+
static readonly [entityKind]: string;
|
|
6
|
+
abstract extensions: string[];
|
|
7
|
+
/**
|
|
8
|
+
* Write the file to the disk
|
|
9
|
+
*/
|
|
10
|
+
abstract writeToFile(): Promise<void>;
|
|
11
|
+
abstract setFileName(value: string): void;
|
|
12
|
+
abstract setFile(file: File): void;
|
|
13
|
+
}
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=fileField.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileField.d.ts","sourceRoot":"","sources":["../../../src/core/fields/fileField.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAEvC,KAAK,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,UAAU,CAAA;AAC9C,8BAAsB,SAAS,CAC3B,KAAK,SAAS,QAAQ,GAAG,QAAQ,EACjC,iBAAiB,SAAS,MAAM,GAAG,MAAM,CAC3C,SAAQ,KAAK,CAAC,KAAK,EAAE,iBAAiB,CAAC;IACrC,gBAAyB,CAAC,UAAU,CAAC,EAAE,MAAM,CAAc;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,CAAA;IAC7B;;OAEG;IACH,QAAQ,CAAC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IACrC,QAAQ,CAAC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IACzC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;CACrC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export { TextField, textField } from './text';
|
|
2
|
+
export type { TextFieldClientConfig, TextFieldConfig } from './text';
|
|
3
|
+
export { PasswordField, passwordField } from './password';
|
|
4
|
+
export type { PasswordFieldClientConfig, PasswordFieldConfig } from './password';
|
|
5
|
+
export { TextAreaField, textAreaField } from './textArea';
|
|
6
|
+
export type { TextAreaFieldClientConfig, TextAreaFieldConfig } from './textArea';
|
|
7
|
+
export { NumberField, numberField } from './number';
|
|
8
|
+
export type { NumberFieldClientConfig, NumberFieldConfig as NumberFieldConfigType } from './number';
|
|
9
|
+
export { TagsField, tagsField } from './tags';
|
|
10
|
+
export type { TagsFieldClientConfig, TagsFieldConfig } from './tags';
|
|
11
|
+
export { PhotoField, photoField } from './photo';
|
|
12
|
+
export type { PhotoFieldClientConfig, PhotoFieldConfig as PhotoFieldConfigType } from './photo';
|
|
13
|
+
export { VideoField, videoField } from './video';
|
|
14
|
+
export type { VideoFieldClientConfig, VideoFieldConfig } from './video';
|
|
15
|
+
export { CheckboxField, checkboxField } from './checkbox';
|
|
16
|
+
export type { CheckboxFieldClientConfig, CheckboxFieldConfig } from './checkbox';
|
|
17
|
+
export { SelectField, selectField } from './select';
|
|
18
|
+
export type { SelectFieldClientConfig, SelectFieldConfigType, SelectOption } from './select';
|
|
19
|
+
export { SelectMultipleField, selectMultipleField } from './selectMultiple';
|
|
20
|
+
export type { SelectMultipleFieldClientConfig, SelectMultipleFieldConfigType } from './selectMultiple';
|
|
21
|
+
export { DocumentField, documentField } from './document';
|
|
22
|
+
export type { DocumentFieldClientConfig, DocumentFieldConfig as DocumentFieldConfigType } from './document';
|
|
23
|
+
export { MapField, mapField } from './map';
|
|
24
|
+
export type { MapFieldClientConfig, MapFieldConfig } from './map';
|
|
25
|
+
export { RichTextField, richTextField } from './richText';
|
|
26
|
+
export type { RichTextFieldClientConfig, RichTextFieldConfig as RichTextFieldConfigType } from './richText';
|
|
27
|
+
export { DateField, dateField } from './date';
|
|
28
|
+
export type { DateFieldClientConfig, DateFieldConfig } from './date';
|
|
29
|
+
export { ColorField, colorField } from './color';
|
|
30
|
+
export type { ColorFieldClientConfig, ColorFieldConfig } from './color';
|
|
31
|
+
export { Field } from './field';
|
|
32
|
+
export type { BaseFieldConfig, FieldClientConfig } from './field';
|
|
33
|
+
export { FileField } from './fileField';
|
|
34
|
+
export { fieldGroup } from './field-group';
|
|
35
|
+
export type { FieldGroup, FieldGroupOptions, FieldGroupConfig } from './field-group';
|
|
36
|
+
import type { TextFieldConfig } from './text';
|
|
37
|
+
import type { NumberFieldConfig } from './number';
|
|
38
|
+
import type { TextAreaFieldConfig } from './textArea';
|
|
39
|
+
import type { TagsFieldConfig } from './tags';
|
|
40
|
+
import type { CheckboxFieldConfig } from './checkbox';
|
|
41
|
+
import type { RichTextFieldConfig } from './richText';
|
|
42
|
+
import type { PasswordFieldConfig } from './password';
|
|
43
|
+
import type { PhotoFieldConfig } from './photo';
|
|
44
|
+
import type { VideoFieldConfig } from './video';
|
|
45
|
+
import type { SelectFieldConfigType } from './select';
|
|
46
|
+
import type { SelectMultipleFieldConfigType } from './selectMultiple';
|
|
47
|
+
import type { DocumentFieldConfig } from './document';
|
|
48
|
+
import type { MapFieldConfig } from './map';
|
|
49
|
+
import type { DateFieldConfig } from './date';
|
|
50
|
+
import type { ColorFieldConfig } from './color';
|
|
51
|
+
/**
|
|
52
|
+
* Union type of all field config types
|
|
53
|
+
* This allows type-safe handling of field configs
|
|
54
|
+
*
|
|
55
|
+
* Each field config has a build() method that creates a Field instance.
|
|
56
|
+
* Use the build() method directly on the config: `fieldConfig.build()`
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* const textConfig = textField({ name: 'title', label: 'Title' })
|
|
61
|
+
* const textInstance = textConfig.build() // Direct build() call
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export type FieldConfig = TextFieldConfig | NumberFieldConfig | TextAreaFieldConfig | TagsFieldConfig | CheckboxFieldConfig | RichTextFieldConfig | PasswordFieldConfig | PhotoFieldConfig | VideoFieldConfig | SelectFieldConfigType | SelectMultipleFieldConfigType | DocumentFieldConfig | MapFieldConfig | DateFieldConfig | ColorFieldConfig;
|
|
65
|
+
//# sourceMappingURL=index.d.ts.map
|