Skip to content

Commit

Permalink
feat: file-max-size (#152)
Browse files Browse the repository at this point in the history
* feat: file size validation

* chore: move multiple-min/multiple-max cfg props upper to multiple

* chore: hide `add more` button on single file mode

* fix: upload-list toolbar layout
  • Loading branch information
nd0ut authored May 17, 2022
1 parent 7f78ddb commit e626a82
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 41 deletions.
9 changes: 5 additions & 4 deletions abstract/Block.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ if (!DOC_READY) {
* @typedef {{
* '*ctxTargetsRegistry': Set<any>;
* '*currentActivity': String;
* '*currentActivityParams': { [key: String]: any };
* '*currentActivityParams': { [key: String]: unknown };
* '*history': String[];
* '*commonProgress': Number;
* '*uploadList': any[];
* '*outputData': any[] | null;
* '*focusedEntry': any | null;
* '*uploadList': String[];
* '*outputData': unknown[] | null;
* '*focusedEntry': unknown | null;
* '*uploadCollection': TypedCollection;
* [key: String]: unknown;
* }} BlockState
Expand Down Expand Up @@ -148,6 +148,7 @@ export class Block extends BaseComponent {
'--cfg-confirm-upload',
'--cfg-init-activity',
'--cfg-done-activity',
'--cfg-max-local-file-size-bytes',
];
cfgProps.forEach((prop) => {
this.bindCssData(prop);
Expand Down
7 changes: 6 additions & 1 deletion blocks/ExternalSource/ExternalSource.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { registerMessage, unregisterMessage } from './messages.js';
import { buildStyles } from './buildStyles.js';
import { queryString } from './query-string.js';

/**
* @typedef {Object} ActivityParams
* @property {String} externalSourceType
*/

/**
* @typedef {Object} State
* @property {Number} counter
Expand Down Expand Up @@ -39,7 +44,7 @@ export class ExternalSource extends Block {
this.bindCssData('--cfg-remote-tab-session-key');

this.registerActivity(this.activityType, () => {
let { externalSourceType } = this.activityParams;
let { externalSourceType } = /** @type {ActivityParams} */ (this.activityParams);

this.set$({
'*activityCaption': `${externalSourceType[0].toUpperCase()}${externalSourceType.slice(1)}`,
Expand Down
52 changes: 44 additions & 8 deletions blocks/FileItem/FileItem.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,23 @@ export class FileItem extends Block {
}
}

/**
* @private
* @param {'success' | 'error'} type
* @param {String} caption
* @param {String} text
*/
_showMessage(type, caption, text) {
let msg = new UiMessage();
msg.caption = caption;
msg.text = text;
msg.isError = type === 'error';
this.set$({
badgeIcon: `badge-${type}`,
'*message': msg,
});
}

initCallback() {
super.initCallback();
this.bindCssData('--cfg-thumb-size');
Expand All @@ -106,6 +123,23 @@ export class FileItem extends Block {
return;
}

this.entry.subscribe('validationErrorMsg', (validationErrorMsg) => {
if (!validationErrorMsg) {
return;
}
this.setAttribute('error', '');
let caption = this.l10n('validation-error') + ': ' + (this.file?.name || this.externalUrl);
this._showMessage('error', caption, validationErrorMsg);
});

this.entry.subscribe('uploadError', (uploadError) => {
if (!uploadError) {
return;
}
let caption = this.l10n('upload-error') + ': ' + (this.file?.name || this.externalUrl);
this._showMessage('error', caption, uploadError);
});

this.entry.subscribe('isUploading', (isUploading) => {
this.$.progressVisible = isUploading;
});
Expand All @@ -118,6 +152,16 @@ export class FileItem extends Block {
this.$.itemName = name || this.externalUrl || this.l10n('file-no-name');
});

this.entry.subscribe('fileSize', (fileSize) => {
let maxFileSize = this.$['*--cfg-max-local-file-size-bytes'];
if (!maxFileSize) {
return;
}
if (fileSize && fileSize > maxFileSize) {
this.entry.setValue('validationErrorMsg', this.l10n('files-max-size-limit-error', { maxFileSize }));
}
});

this.entry.subscribe('externalUrl', (externalUrl) => {
this.$.itemName = this.entry.getValue('fileName') || externalUrl || this.l10n('file-no-name');
});
Expand Down Expand Up @@ -243,14 +287,6 @@ export class FileItem extends Block {
this.$.progressValue = 0;
this.setAttribute('error', '');
this.removeAttribute('uploading');
let msg = new UiMessage();
msg.caption = this.l10n('upload-error') + ': ' + (this.file?.name || this.externalUrl);
msg.text = error;
msg.isError = true;
this.set$({
badgeIcon: 'badge-error',
'*message': msg,
});
this.entry.setValue('uploadProgress', 0);
this.entry.setValue('uploadError', error);
}
Expand Down
35 changes: 21 additions & 14 deletions blocks/UploadList/UploadList.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ export class UploadList extends Block {
}
}

/** @private */
_handleCollectionUpdate() {
this._updateButtonsState();
this._updateCountLimitMessage();
}

/** @private */
_updateButtonsState() {
let itemIds = this.uploadCollection.items();
Expand All @@ -129,6 +135,7 @@ export class UploadList extends Block {
total: filesCount,
uploaded: 0,
uploading: 0,
validationFailed: 0,
};
for (let id of itemIds) {
let item = this.uploadCollection.read(id);
Expand All @@ -137,18 +144,23 @@ export class UploadList extends Block {
} else if (item.getValue('isUploading')) {
summary.uploading += 1;
}
if (item.getValue('validationErrorMsg')) {
summary.validationFailed += 1;
}
}
let allUploaded = summary.total === summary.uploaded;
let { passed: fitCountRestrictions, tooMany, exact } = this._validateFilesCount();
let fitValidation = summary.validationFailed === 0;

this.set$({
doneBtnHidden: !allUploaded,
doneBtnDisabled: !fitCountRestrictions,
doneBtnDisabled: !fitCountRestrictions || !fitValidation,

uploadBtnHidden: allUploaded,
uploadBtnDisabled: summary.uploading > 0 || !fitCountRestrictions,
uploadBtnDisabled: summary.uploading > 0 || !fitCountRestrictions || !fitValidation,

addMoreBtnDisabled: tooMany || exact,
addMoreBtnHidden: exact && !this.$['*--cfg-multiple'],
});

if (!this.$['*--cfg-confirm-upload'] && fitCountRestrictions && allUploaded) {
Expand All @@ -168,29 +180,24 @@ export class UploadList extends Block {
});
});

const handleStateUpdate = () => {
this._updateButtonsState();
this._updateCountLimitMessage();
};

this.sub('*--cfg-multiple', handleStateUpdate);
this.sub('*--cfg-multiple-min', handleStateUpdate);
this.sub('*--cfg-multiple-max', handleStateUpdate);
this.sub('*--cfg-multiple', () => this._handleCollectionUpdate());
this.sub('*--cfg-multiple-min', () => this._handleCollectionUpdate());
this.sub('*--cfg-multiple-max', () => this._handleCollectionUpdate());

// TODO: could be performance issue on many files
// there is no need to update buttons state on every progress tick
this.uploadCollection.observe(() => {
handleStateUpdate();
this._handleCollectionUpdate();
});

this.sub('*uploadList', (/** @type {String[]} */ list) => {
this.sub('*uploadList', (list) => {
if (list?.length === 0 && !this.$['*--cfg-show-empty-list']) {
this.cancelFlow();
this.ref.files.innerHTML = '';
return;
}

handleStateUpdate();
this._handleCollectionUpdate();

this.set$({
hasFiles: list.length > 0,
Expand Down Expand Up @@ -239,7 +246,7 @@ UploadList.template = /*html*/ `
class="cancel-btn secondary-btn"
set="onclick: onCancel;"
l10n="clear"></button>
<div></div>
<div class="toolbar-spacer"></div>
<button
class="add-more-btn secondary-btn"
set="onclick: onAdd; @disabled: addMoreBtnDisabled; @hidden: addMoreBtnHidden"
Expand Down
10 changes: 7 additions & 3 deletions blocks/UploadList/upload-list.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ uc-upload-list .files {
}

uc-upload-list .toolbar {
display: grid;
grid-gap: var(--gap-mid);
grid-template-columns: min-content 1fr min-content min-content;
display: flex;
gap: var(--gap-mid);
justify-content: space-between;
padding: var(--gap-mid);
background-color: var(--clr-background);
border-top: var(--border-light);
}

uc-upload-list .toolbar-spacer {
flex: 1;
}
9 changes: 4 additions & 5 deletions blocks/themes/uc-basic/config.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@
:host {
--cfg-pubkey: 'YOUR_PUBLIC_KEY';
--cfg-multiple: 1;
--cfg-multiple-min: 0;
--cfg-multiple-max: 0;

--cfg-confirm-upload: 1;
--cfg-img-only: 0;
--cfg-accept: '';
--cfg-store: 1;
--cfg-camera-mirror: 1;
--cfg-source-list: 'local, url, camera, dropbox, gdrive, facebook';
--cfg-max-local-file-size-bytes: 30000;
--cfg-max-local-file-size-bytes: 0;
--cfg-thumb-size: 76;
--cfg-show-empty-list: 0;
--cfg-use-local-image-editor: 0;
--cfg-use-cloud-image-editor: 1;

/* value `0` means limit is disabled */
--cfg-multiple-min: 0;
--cfg-multiple-max: 0;

--cfg-modal-scroll-lock: 1;
--cfg-modal-backdrop-strokes: 1;

Expand Down
3 changes: 3 additions & 0 deletions blocks/themes/uc-basic/l10n.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
--l10n-are-you-sure: 'Are you sure?';
--l10n-selected-count: 'Selected:';
--l10n-upload-error: 'Upload error';
--l10n-validation-error: 'Validation error';
--l10n-no-files: 'No files selected';
--l10n-browse: 'Browse';

Expand Down Expand Up @@ -82,4 +83,6 @@
--l10n-files-count-limit-error-title: 'Files count limit overflow';
--l10n-files-count-limit-error-too-few: 'You’ve chosen {{total}}. At least {{min}} required.';
--l10n-files-count-limit-error-too-many: 'You’ve chosen too many files. {{max}} is maximum.';

--l10n-files-max-size-limit-error: 'File is too big. Max file size is {{maxFileSize}} bytes.';
}
26 changes: 20 additions & 6 deletions docs/configuration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,37 @@ We use the Data-in-CSS approach to set configurations.
This is the list of pre-defined parameters used by default in our uploader builds:

```css
.uc-wgt-cfg,
.uc-wgt-common,
:where(.uc-wgt-cfg, .uc-wgt-common),
:host {
--cfg-pubkey: 'demopublickey';
--cfg-pubkey: 'YOUR_PUBLIC_KEY';
--cfg-multiple: 1;
--cfg-multiple-min: 0;
--cfg-multiple-max: 0;
--cfg-confirm-upload: 1;
--cfg-img-only: 0;
--cfg-accept: '';
--cfg-store: 1;
--cfg-camera-mirror: 1;
--cfg-source-list: 'local, url, camera, dropbox, gdrive, facebook';
--cfg-multiple-max: 10;
--cfg-max-local-file-size-bytes: 30000;
--cfg-max-local-file-size-bytes: 0;
--cfg-thumb-size: 76;
--cfg-show-empty-list: 0;
--cfg-use-local-image-editor: 0;
--cfg-use-cloud-image-editor: 0;
--cfg-use-cloud-image-editor: 1;

--cfg-modal-scroll-lock: 1;
--cfg-modal-backdrop-strokes: 1;

--cfg-source-list-wrap: 1;

--cfg-init-activity: 'start-from';
--cfg-done-activity: 'start-from';

--cfg-data-output-console: 1;
--cfg-data-output-fire-events: 1;
--cfg-data-output-from: '*dataOutput';
--cfg-data-output-form-value: 1;

--cfg-remote-tab-session-key: '';
}
```
Expand Down

0 comments on commit e626a82

Please sign in to comment.