Skip to content

Commit 89ff7d1

Browse files
committed
Chat FU: attach files which fail validation should block send button
1 parent 29771bc commit 89ff7d1

File tree

5 files changed

+93
-5
lines changed

5 files changed

+93
-5
lines changed

packages/devextreme/js/__internal/ui/chat/message_box/chat_text_area.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import type { OptionChanged } from '@ts/core/widget/types';
2020
import type { SupportedKeys } from '@ts/core/widget/widget';
2121
import Widget from '@ts/core/widget/widget';
2222
import FileUploader from '@ts/ui/file_uploader/file_uploader';
23-
import type { CancelButtonClickEvent, Properties as FileUploaderProperties } from '@ts/ui/file_uploader/file_uploader.types';
23+
import type { CancelButtonClickEvent, FileValidationErrorEvent, Properties as FileUploaderProperties } from '@ts/ui/file_uploader/file_uploader.types';
2424
import Informer from '@ts/ui/informer/informer';
2525
import type { TextAreaProperties } from '@ts/ui/m_text_area';
2626
import TextArea from '@ts/ui/m_text_area';
@@ -332,6 +332,7 @@ class ChatTextArea extends TextArea<Properties> {
332332
onUploaded: (e) => this._fileUploaderOnUploaded(e),
333333
onCancelButtonClick: (e) => this._fileUploaderOnCancelButtonClick(e),
334334
onFileLimitReached: () => this._fileUploaderFileLimitReached(),
335+
onFileValidationError: (e) => this._fileUploaderFileValidationError(e),
335336
};
336337
}
337338

@@ -344,17 +345,21 @@ class ChatTextArea extends TextArea<Properties> {
344345
fileUploaderOptions.onValueChanged?.(e);
345346
}
346347

347-
_fileUploaderOnUploadStarted(e: UploadStartedEvent): void {
348-
const { file } = e;
349-
const { fileUploaderOptions = {} } = this.option();
350-
348+
_addFileToMap(file: File): void {
351349
this._filesToSend?.set(file, {
352350
readyToSend: false,
353351
name: file.name,
354352
size: file.size,
355353
});
356354
this._toggleButtonDisableState();
355+
}
356+
357+
_fileUploaderOnUploadStarted(e: UploadStartedEvent): void {
358+
const { file } = e;
359+
360+
this._addFileToMap(file);
357361

362+
const { fileUploaderOptions = {} } = this.option();
358363
fileUploaderOptions.onUploadStarted?.(e);
359364
}
360365

@@ -390,6 +395,12 @@ class ChatTextArea extends TextArea<Properties> {
390395
this._updateInputHeight();
391396
}
392397

398+
_fileUploaderFileValidationError(e: FileValidationErrorEvent): void {
399+
const { file } = e;
400+
401+
this._addFileToMap(file);
402+
}
403+
393404
_toggleButtonDisableState(state?: boolean): void {
394405
const shouldDisable = state ?? !this._isMessageCanBeSent();
395406
this._sendButton?.option('disabled', shouldDisable);

packages/devextreme/js/__internal/ui/file_uploader/file_uploader.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class FileUploader extends Editor<FileUploaderProperties> {
138138

139139
_filesUploadedAction?: (event?: Record<string, unknown>) => void;
140140

141+
_fileValidationErrorAction?: (event?: Record<string, unknown>) => void;
142+
141143
_uploadedAction?: (event?: Record<string, unknown>) => void;
142144

143145
_beforeSendAction?: (event?: Record<string, unknown>) => void;
@@ -207,6 +209,7 @@ class FileUploader extends Editor<FileUploaderProperties> {
207209
onUploadStarted: null,
208210
onUploaded: null,
209211
onFilesUploaded: null,
212+
onFileValidationError: null,
210213
onProgress: null,
211214
onUploadError: null,
212215
onUploadAborted: null,
@@ -312,6 +315,7 @@ class FileUploader extends Editor<FileUploaderProperties> {
312315
this._createUploadStartedAction();
313316
this._createUploadedAction();
314317
this._createFilesUploadedAction();
318+
this._createFileValidationErrorAction();
315319
this._createProgressAction();
316320
this._createUploadErrorAction();
317321
this._createUploadAbortedAction();
@@ -617,6 +621,10 @@ class FileUploader extends Editor<FileUploaderProperties> {
617621
this._filesUploadedAction = this._createActionByOption('onFilesUploaded', { excludeValidators: ['readOnly'] });
618622
}
619623

624+
_createFileValidationErrorAction(): void {
625+
this._fileValidationErrorAction = this._createActionByOption('onFileValidationError', { excludeValidators: ['readOnly'] });
626+
}
627+
620628
_createProgressAction(): void {
621629
this._progressAction = this._createActionByOption('onProgress', { excludeValidators: ['readOnly'] });
622630
}
@@ -767,6 +775,8 @@ class FileUploader extends Editor<FileUploaderProperties> {
767775
if (!file.isValidMinSize) {
768776
file.$statusMessage.append(this._createValidationElement('invalidMinFileSizeMessage'));
769777
}
778+
779+
this._fileValidationErrorAction?.({ file: file.value });
770780
$fileContainer.addClass(FILEUPLOADER_INVALID_CLASS);
771781
}
772782
}

packages/devextreme/js/__internal/ui/file_uploader/file_uploader.types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ export interface FileUploaderChunkUploadResponse {
114114
error?: string;
115115
}
116116

117+
export type FileValidationErrorEvent = NativeEventInfo<FileUploader> & {
118+
readonly file: File;
119+
};
120+
117121
export type CancelButtonClickEvent = NativeEventInfo<InteractionEvent> & {
118122
readonly file?: File;
119123
};
@@ -146,6 +150,8 @@ export interface Properties extends PublicProperties {
146150
onCancelButtonClick?: (e: CancelButtonClickEvent) => void;
147151

148152
onFileLimitReached?: (e: FileLimitReachedEvent) => void;
153+
154+
onFileValidationError?: (e: FileValidationErrorEvent) => void;
149155
}
150156

151157
export interface FileUploaderProperties extends Properties,

packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/fileUploader.tests.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3670,6 +3670,51 @@ QUnit.module('uploading events', moduleConfig, () => {
36703670

36713671
$cancelButton.trigger('dxclick');
36723672
});
3673+
3674+
QUnit.test('onFileValidationError event should rise if file has not allowed extension', function(assert) {
3675+
assert.expect(2);
3676+
3677+
const $element = $('#fileuploader').dxFileUploader({
3678+
uploadMode: 'instantly',
3679+
allowedFileExtensions: ['.pdf'],
3680+
onFileValidationError: ({ file }) => {
3681+
assert.ok(true, 'onFileValidationError is called');
3682+
assert.strictEqual(file, fakeFile, 'file is passed');
3683+
},
3684+
});
3685+
3686+
simulateFileChoose($element, fakeFile);
3687+
});
3688+
3689+
QUnit.test('onFileValidationError event should rise if file has size bigger than maxFileSize', function(assert) {
3690+
assert.expect(2);
3691+
3692+
const $element = $('#fileuploader').dxFileUploader({
3693+
uploadMode: 'instantly',
3694+
maxFileSize: 1000,
3695+
onFileValidationError: ({ file }) => {
3696+
assert.ok(true, 'onFileValidationError is called');
3697+
assert.strictEqual(file, fakeFile2, 'file is passed');
3698+
},
3699+
});
3700+
3701+
simulateFileChoose($element, fakeFile2);
3702+
});
3703+
3704+
QUnit.test('onFileValidationError event should rise if file has size less than minFileSize', function(assert) {
3705+
assert.expect(2);
3706+
3707+
const $element = $('#fileuploader').dxFileUploader({
3708+
uploadMode: 'instantly',
3709+
minFileSize: 5000,
3710+
onFileValidationError: ({ file }) => {
3711+
assert.ok(true, 'onFileValidationError is called');
3712+
assert.strictEqual(file, fakeFile2, 'file is passed');
3713+
},
3714+
});
3715+
3716+
simulateFileChoose($element, fakeFile2);
3717+
});
36733718
});
36743719

36753720
QUnit.module('keyboard navigation', moduleConfig, () => {

packages/devextreme/testing/tests/DevExpress.ui.widgets/chatParts/chatTextArea.tests.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,22 @@ QUnit.module('ChatTextArea', moduleConfig, () => {
526526

527527
assert.strictEqual(this.sendButton.option('disabled'), true);
528528
});
529+
530+
QUnit.test('send button should be disabled after adding files and some of them fail validation', function(assert) {
531+
this.reinit({
532+
fileUploaderOptions: {
533+
uploadFile: () => {},
534+
allowedFileExtensions: ['.png'],
535+
},
536+
});
537+
const fileUploader = this.getFileUploader();
538+
fileUploader.option('value', [fakeFile, { name: 'img.jpg', size: 1 }]);
539+
fileUploader.upload();
540+
541+
this.clock.tick();
542+
543+
assert.strictEqual(this.sendButton.option('disabled'), true, 'send button is disabled after adding file that fail validation');
544+
});
529545
});
530546

531547
QUnit.module('Informer integration', {

0 commit comments

Comments
 (0)