Skip to content

Commit a2b4c12

Browse files
committed
[Feat]: #2100 file validation add + refactor file upload
1 parent b9122be commit a2b4c12

File tree

3 files changed

+66
-32
lines changed

3 files changed

+66
-32
lines changed

client/packages/lowcoder/src/comps/comps/fileComp/draggerUpload.tsx

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import {
1111
multiChangeAction,
1212
} from "lowcoder-core";
1313
import { hasIcon } from "comps/utils";
14-
import { messageInstance } from "lowcoder-design/src/components/GlobalInstances";
15-
import { resolveValue, resolveParsedValue, commonProps } from "./fileComp";
14+
import { resolveValue, resolveParsedValue, commonProps, validateFile } from "./fileComp";
1615
import { FileStyleType, AnimationStyleType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants";
1716
import { ImageCaptureModal } from "./ImageCaptureModal";
1817
import { v4 as uuidv4 } from "uuid";
@@ -152,6 +151,7 @@ interface DraggerUploadProps {
152151
minSize: number;
153152
maxSize: number;
154153
maxFiles: number;
154+
fileNamePattern: string;
155155
uploadType: "single" | "multiple" | "directory";
156156
text: string;
157157
dragHintText?: string;
@@ -254,21 +254,11 @@ export const DraggerUpload = (props: DraggerUploadProps) => {
254254
$auto={autoHeight}
255255
capture={props.forceCapture}
256256
openFileDialogOnClick={!(props.forceCapture && !isMobile)}
257-
beforeUpload={(file) => {
258-
if (!file.size || file.size <= 0) {
259-
messageInstance.error(`${file.name} ` + trans("file.fileEmptyErrorMsg"));
260-
return AntdUpload.LIST_IGNORE;
261-
}
262-
263-
if (
264-
(!!props.minSize && file.size < props.minSize) ||
265-
(!!props.maxSize && file.size > props.maxSize)
266-
) {
267-
messageInstance.error(`${file.name} ` + trans("file.fileSizeExceedErrorMsg"));
268-
return AntdUpload.LIST_IGNORE;
269-
}
270-
return true;
271-
}}
257+
beforeUpload={(file) => validateFile(file, {
258+
minSize: props.minSize,
259+
maxSize: props.maxSize,
260+
fileNamePattern: props.fileNamePattern,
261+
})}
272262
onChange={handleOnChange}
273263
>
274264
<p className="ant-upload-drag-icon">

client/packages/lowcoder/src/comps/comps/fileComp/fileComp.tsx

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const validationChildren = {
9797
minSize: FileSizeControl,
9898
maxSize: FileSizeControl,
9999
maxFiles: NumberControl,
100+
fileNamePattern: StringControl,
100101
};
101102

102103
const commonChildren = {
@@ -127,6 +128,11 @@ const commonValidationFields = (children: RecordConstructorToComp<typeof validat
127128
placeholder: "10kb",
128129
tooltip: trans("file.maxSizeTooltip"),
129130
}),
131+
children.fileNamePattern.propertyView({
132+
label: trans("file.fileNamePattern"),
133+
placeholder: trans("file.fileNamePatternPlaceholder"),
134+
tooltip: trans("file.fileNamePatternTooltip"),
135+
}),
130136
];
131137

132138
export const commonProps = (
@@ -141,6 +147,49 @@ export const commonProps = (
141147
customRequest: (options: UploadRequestOption) => options.onSuccess && options.onSuccess({}), // Override the default upload logic and do not upload to the specified server
142148
});
143149

150+
export interface FileValidationOptions {
151+
minSize?: number;
152+
maxSize?: number;
153+
fileNamePattern?: string;
154+
}
155+
156+
157+
export const validateFile = (
158+
file: { name: string; size?: number },
159+
options: FileValidationOptions
160+
): boolean | typeof AntdUpload.LIST_IGNORE => {
161+
// Empty file validation
162+
if (!file.size || file.size <= 0) {
163+
messageInstance.error(`${file.name} ` + trans("file.fileEmptyErrorMsg"));
164+
return AntdUpload.LIST_IGNORE;
165+
}
166+
167+
// File size validation
168+
if (
169+
(!!options.minSize && file.size < options.minSize) ||
170+
(!!options.maxSize && file.size > options.maxSize)
171+
) {
172+
messageInstance.error(`${file.name} ` + trans("file.fileSizeExceedErrorMsg"));
173+
return AntdUpload.LIST_IGNORE;
174+
}
175+
176+
// File name pattern validation
177+
if (options.fileNamePattern) {
178+
try {
179+
const pattern = new RegExp(options.fileNamePattern);
180+
if (!pattern.test(file.name)) {
181+
messageInstance.error(`${file.name} ` + trans("file.fileNamePatternErrorMsg"));
182+
return AntdUpload.LIST_IGNORE;
183+
}
184+
} catch (e) {
185+
messageInstance.error(trans("file.invalidFileNamePatternMsg", { error: String(e) }));
186+
return AntdUpload.LIST_IGNORE;
187+
}
188+
}
189+
190+
return true;
191+
};
192+
144193
const getStyle = (style: FileStyleType) => {
145194
return css`
146195
.ant-btn {
@@ -361,21 +410,11 @@ const Upload = (
361410
{...commonProps(props)}
362411
$style={style}
363412
fileList={fileList}
364-
beforeUpload={(file) => {
365-
if (!file.size || file.size <= 0) {
366-
messageInstance.error(`${file.name} ` + trans("file.fileEmptyErrorMsg"));
367-
return AntdUpload.LIST_IGNORE;
368-
}
369-
370-
if (
371-
(!!props.minSize && file.size < props.minSize) ||
372-
(!!props.maxSize && file.size > props.maxSize)
373-
) {
374-
messageInstance.error(`${file.name} ` + trans("file.fileSizeExceedErrorMsg"));
375-
return AntdUpload.LIST_IGNORE;
376-
}
377-
return true;
378-
}}
413+
beforeUpload={(file) => validateFile(file, {
414+
minSize: props.minSize,
415+
maxSize: props.maxSize,
416+
fileNamePattern: props.fileNamePattern,
417+
})}
379418
onChange={handleOnChange}
380419

381420
>

client/packages/lowcoder/src/i18n/locales/en.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,6 +1949,11 @@ export const en = {
19491949
"dragAreaText": "Click or drag file to this area to upload",
19501950
"dragAreaHint": "Support for a single or bulk upload. Strictly prohibited from uploading company data or other banned files.",
19511951
"dragHintText": "Hint Text",
1952+
"fileNamePattern": "File Name Pattern",
1953+
"fileNamePatternTooltip": "A regular expression pattern to validate file names (e.g., '^[a-zA-Z0-9_-]+\\.[a-z]+$' for alphanumeric names). Leave empty to allow all file names.",
1954+
"fileNamePatternPlaceholder": "^[a-zA-Z0-9_-]+\\.[a-z]+$",
1955+
"fileNamePatternErrorMsg": "Upload Failed. The File Name Does Not Match the Required Pattern.",
1956+
"invalidFileNamePatternMsg": "Invalid File Name Pattern: {error}",
19521957
},
19531958
"date": {
19541959
"format": "Format",

0 commit comments

Comments
 (0)