@carbon/ibm-cloud-cognitive-cdai
Version:
Carbon for Cloud & Cognitive CD&AI UI components
576 lines (574 loc) • 23.7 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
import _defineProperty from "@babel/runtime/helpers/defineProperty";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import _createClass from "@babel/runtime/helpers/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/inherits";
import _regeneratorRuntime from "@babel/runtime/regenerator";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
//
// Copyright IBM Corp. 2020, 2020
//
// This source code is licensed under the Apache-2.0 license found in the
// LICENSE file in the root directory of this source tree.
//
import React from 'react';
import PropTypes from 'prop-types';
import { FileUploaderDropContainer, FileUploaderItem, FormItem, TextInput, Button } from 'carbon-components-react';
import { parseFileFromUrl } from '../../component_helpers/FileHelper';
import { countFiles as _countFiles, sortFiles, uuid, validateFileAdded as _validateFileAdded, FILE_UPLOAD_STATUS } from './helpers';
import { idePrefix } from '../../globals/js/settings';
// TODO(ritch): move to cosntants file
var IdeImporting = /*#__PURE__*/function (_React$Component) {
function IdeImporting(props) {
var _this;
_classCallCheck(this, IdeImporting);
_this = _callSuper(this, IdeImporting, [props]);
_this.currentIndex = -1;
_this.state = {
open: props.open,
urlInput: '',
urlInputIsValid: false,
filesToUpload: props.initialFiles,
finished: false
};
_this.handleFilesAdded = _this.handleFilesAdded.bind(_this);
return _this;
}
_inherits(IdeImporting, _React$Component);
return _createClass(IdeImporting, [{
key: "componentDidMount",
value: function componentDidMount() {
this.mounted = true;
}
}, {
key: "componentWillUnmount",
value: function componentWillUnmount() {
this.mounted = false;
}
}, {
key: "countFiles",
value: function countFiles() {
return _countFiles(this.state.filesToUpload);
}
}, {
key: "getVerbLabel",
value: function getVerbLabel() {
var _this$props = this.props,
enableUpload = _this$props.enableUpload,
verbLabel = _this$props.verbLabel;
if (verbLabel) {
return verbLabel;
} else if (enableUpload) {
return 'uploaded';
}
return 'imported';
}
}, {
key: "getDescription",
value: function getDescription() {
if (this.props.enableUpload) {
return this.props.uploadDescription;
}
return this.props.importDescription;
}
}, {
key: "updateFileToUploadState",
value: function updateFileToUploadState(uuid, update) {
this.setState(function (state) {
var updatedFiles = [];
var _iterator = _createForOfIteratorHelper(state.filesToUpload),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var fileInfo = _step.value;
if (fileInfo.uuid === uuid) {
updatedFiles.push(_objectSpread(_objectSpread({}, fileInfo), update));
} else {
updatedFiles.push(fileInfo);
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return _objectSpread(_objectSpread({}, state), {}, {
filesToUpload: updatedFiles
});
});
}
}, {
key: "isValidUrl",
value: function isValidUrl(url) {
var onValidateUrl = this.props.onValidateUrl;
if (typeof onValidateUrl === 'function') {
return onValidateUrl(url);
}
var re = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
return !!re.exec(url);
}
}, {
key: "getInvalidExtensionText",
value: function getInvalidExtensionText() {
var validExtensionsText = this.props.mustBeExtensionTextSingular;
if (this.props.validExtensions.length > 1) {
validExtensionsText = this.props.mustBeExtensionTextPlural;
}
validExtensionsText = validExtensionsText.replace('$EXT', this.props.validExtensions.join(', '));
return "".concat(this.props.extensionIsInvalidText, " ").concat(validExtensionsText);
}
}, {
key: "validateFileAdded",
value: function validateFileAdded(fileToUpload) {
return _validateFileAdded(fileToUpload, this.props, this.getInvalidExtensionText.bind(this));
}
}, {
key: "handleFileAdded",
value: function () {
var _handleFileAdded = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(fileToUpload) {
var _e$message$split, _e$message$split2, errorSubject, errorBody;
return _regeneratorRuntime.wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
if (this.mounted) {
_context.next = 2;
break;
}
return _context.abrupt("return");
case 2:
if (!fileToUpload.invalid) {
_context.next = 4;
break;
}
return _context.abrupt("return");
case 4:
_context.prev = 4;
this.updateFileToUploadState(fileToUpload.uuid, {
status: FILE_UPLOAD_STATUS.UPLOADING
});
_context.next = 8;
return this.props.onFileAdded(fileToUpload);
case 8:
if (this.mounted) {
_context.next = 10;
break;
}
return _context.abrupt("return");
case 10:
if (this.props.allowValidFileEditing || this.props.enableUpload === false) {
this.updateFileToUploadState(fileToUpload.uuid, {
status: FILE_UPLOAD_STATUS.EDIT,
invalid: false
});
} else {
this.updateFileToUploadState(fileToUpload.uuid, {
status: FILE_UPLOAD_STATUS.COMPLETE,
invalid: false
});
}
_context.next = 18;
break;
case 13:
_context.prev = 13;
_context.t0 = _context["catch"](4);
_e$message$split = _context.t0.message.split(':'), _e$message$split2 = _slicedToArray(_e$message$split, 2), errorSubject = _e$message$split2[0], errorBody = _e$message$split2[1];
this.updateFileToUploadState(fileToUpload.uuid, {
status: FILE_UPLOAD_STATUS.EDIT,
invalid: true,
errorSubject: errorSubject,
errorBody: errorBody
});
throw _context.t0;
case 18:
case "end":
return _context.stop();
}
}, _callee, this, [[4, 13]]);
}));
function handleFileAdded(_x) {
return _handleFileAdded.apply(this, arguments);
}
return handleFileAdded;
}()
}, {
key: "getNextIndex",
value: function getNextIndex() {
this.currentIndex++;
return this.currentIndex;
}
}, {
key: "createFileToUpload",
value: function createFileToUpload(info) {
var file = info.file,
url = info.url;
if (url) {
file = {
name: parseFileFromUrl(url)
};
}
var validation = this.validateFileAdded({
file: file,
url: url
});
return _objectSpread({
index: this.getNextIndex(),
file: file,
url: url,
uuid: uuid(),
status: FILE_UPLOAD_STATUS.EDIT
}, validation);
}
}, {
key: "handleFilesAdded",
value: function handleFilesAdded(e, _ref) {
var _this2 = this;
var addedFiles = _ref.addedFiles;
e.stopPropagation();
if (!this.props.multiple) {
addedFiles = [addedFiles[0]];
}
var mappedFiles = addedFiles.map(function (file) {
return _this2.createFileToUpload({
file: file
});
});
this.setState(function (state) {
return {
filesToUpload: [].concat(_toConsumableArray(state.filesToUpload), _toConsumableArray(mappedFiles))
};
});
var _iterator2 = _createForOfIteratorHelper(mappedFiles),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var fileToUpload = _step2.value;
this.handleFileAdded(fileToUpload).catch(function (err) {
console.warn(err);
});
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
}, {
key: "handleUrlAdded",
value: function handleUrlAdded(addedFiles) {
var _this3 = this;
var mappedFiles = addedFiles.map(function (url) {
return _this3.createFileToUpload({
url: url
});
});
this.setState(function (state) {
return {
filesToUpload: [].concat(_toConsumableArray(state.filesToUpload), _toConsumableArray(mappedFiles))
};
});
var _iterator3 = _createForOfIteratorHelper(mappedFiles),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var fileToUpload = _step3.value;
this.handleFileAdded(fileToUpload);
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
}
}, {
key: "handleRemoveFile",
value: function handleRemoveFile(clickedUuid) {
var _this4 = this,
_this$props$onFileRem,
_this$props2;
this.setState(function (state) {
var filesToUpload = _this4.state.filesToUpload;
return _objectSpread(_objectSpread({}, state), {}, {
filesToUpload: filesToUpload.filter(function (_ref2) {
var uuid = _ref2.uuid;
return clickedUuid !== uuid;
})
});
});
(_this$props$onFileRem = (_this$props2 = this.props).onFileRemoved) === null || _this$props$onFileRem === void 0 || _this$props$onFileRem.call(_this$props2, clickedUuid);
}
}, {
key: "getSortedFiles",
value: function getSortedFiles() {
var filesToUpload = this.state.filesToUpload;
// ensure files are sorted in groups and by order added (index)
// also ensures that the import status files are at the top
// eg. errors should show at the top, followed by pending,
// then finally completed files
return filesToUpload.sort(function (a, b) {
return sortFiles(a, b, filesToUpload.length);
});
}
}, {
key: "renderFilesToUpload",
value: function renderFilesToUpload(counts) {
var _this5 = this;
var _this$props3 = this.props,
multiple = _this$props3.multiple,
singleFileLabel = _this$props3.singleFileLabel,
fileDropHeader = _this$props3.fileDropHeader,
hideImport = _this$props3.hideImport;
return /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "--file-status"),
style: {
width: '100%'
}
}, /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "--file-list ").concat(idePrefix, "-hide-import")
}, /*#__PURE__*/React.createElement("h6", {
className: "".concat(idePrefix, "--file-list-status")
}, multiple && /*#__PURE__*/React.createElement("span", null, counts.finished, " / ", counts.total, ' '), !hideImport && !multiple && /*#__PURE__*/React.createElement("span", null, singleFileLabel), !hideImport && this.getVerbLabel()), hideImport && /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "--file-header-label")
}, fileDropHeader), this.getSortedFiles().map(function (_ref3) {
var file = _ref3.file,
uuid = _ref3.uuid,
status = _ref3.status,
invalid = _ref3.invalid,
errorSubject = _ref3.errorSubject,
errorBody = _ref3.errorBody;
return /*#__PURE__*/React.createElement(FileUploaderItem, {
key: uuid,
uuid: uuid,
name: file.name,
status: status,
invalid: invalid,
errorSubject: errorSubject,
errorBody: errorBody,
onDelete: _this5.handleRemoveFile.bind(_this5, uuid)
});
})));
}
}, {
key: "shouldDisableInput",
value: function shouldDisableInput() {
var multiple = this.props.multiple;
var single = !multiple;
var counts = this.countFiles();
if (single && counts.total > 0 || single && this.state.urlInput) {
// disable inputs in single mode
// when a file has been selected
// or any characters are entered into the url input
return true;
}
if (counts.uploading > 0) {
// disable inputs during upload
return true;
}
return false;
}
}, {
key: "renderFileMode",
value: function renderFileMode() {
var _this$props4 = this.props,
multiple = _this$props4.multiple,
enableFileDrop = _this$props4.enableFileDrop,
hideImport = _this$props4.hideImport,
fileDropHeader = _this$props4.fileDropHeader;
if (!enableFileDrop) {
return null;
}
var disabled = this.shouldDisableInput();
var fileUploaderProps = {
multiple: multiple,
disabled: disabled,
labelText: multiple ? this.props.fileDropLabelPlural : this.props.fileDropLabelSingular,
name: 'name',
accept: [].concat(_toConsumableArray(this.props.validExtensions.map(function (ext) {
return ".".concat(ext);
})), ['*'])
};
return hideImport && disabled ? null : /*#__PURE__*/React.createElement(FormItem, null, hideImport ? /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "--file-header-label")
}, fileDropHeader) : /*#__PURE__*/React.createElement("h5", null, fileDropHeader), /*#__PURE__*/React.createElement(FileUploaderDropContainer, _extends({}, fileUploaderProps, {
onAddFiles: this.handleFilesAdded
})));
}
}, {
key: "handleUrlChanged",
value: function handleUrlChanged(e) {
this.setState({
urlInput: e.target.value,
urlInputIsValid: this.isValidUrl(e.target.value)
});
}
}, {
key: "renderUrlMode",
value: function renderUrlMode() {
var _this6 = this;
var _this$props5 = this.props,
multiple = _this$props5.multiple,
enableUrlInput = _this$props5.enableUrlInput;
var urlInputIsValid = this.state.urlInputIsValid;
if (!enableUrlInput) {
return null;
}
var inputProps = {
key: 'importing-input',
id: 'ide-input-modal-url-input',
labelText: this.props.urlInputLabel,
value: this.state.urlInput,
disabled: !multiple && this.state.filesToUpload.length > 0,
invalid: !!(this.state.urlInput && !urlInputIsValid),
invalidText: this.props.invalidUrlText,
className: "".concat(idePrefix, "-importing-url-input-field"),
onChange: function onChange(e) {
e.stopPropagation();
_this6.handleUrlChanged(e);
}
};
var buttonProps = {
disabled: !urlInputIsValid || !this.state.urlInput,
size: 'field',
onClick: function onClick() {
/* istanbul ignore else */
if (_this6.state.urlInput) {
_this6.handleUrlAdded([_this6.state.urlInput]);
_this6.setState({
urlInput: ''
});
}
}
};
return /*#__PURE__*/React.createElement(FormItem, {
className: "".concat(idePrefix, "-file-by-url")
}, /*#__PURE__*/React.createElement("h5", null, this.props.urlInputHeader), /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "-importing-flex-input")
}, /*#__PURE__*/React.createElement(TextInput, inputProps), /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "-importing-flex-button")
}, /*#__PURE__*/React.createElement(Button, buttonProps, this.props.addUrlBttonLabel))));
}
}, {
key: "renderText",
value: function renderText() {
return /*#__PURE__*/React.createElement("p", {
className: "".concat(idePrefix, "-importing-description")
}, this.getDescription());
}
}, {
key: "render",
value: function render() {
var counts = this.countFiles();
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("div", {
className: "".concat(idePrefix, "-import-container")
}, this.renderText(), this.renderFileMode(), this.renderUrlMode(), counts.total > 0 ? this.renderFilesToUpload(counts) : null));
}
}]);
}(React.Component);
export { IdeImporting as default };
IdeImporting.propTypes = {
addUrlBttonLabel: PropTypes.string,
allowInvalidFilenameInUrl: PropTypes.bool,
allowValidFileEditing: PropTypes.bool,
autoCloseDelay: PropTypes.number,
defaultUncaughtErrorBody: PropTypes.string,
defaultUncaughtErrorSubject: PropTypes.string,
dropDescription: PropTypes.string,
enableFileDrop: PropTypes.bool,
enableUpload: PropTypes.bool,
enableUrlInput: PropTypes.bool,
extensionIsInvalidText: PropTypes.string,
extensionIsRequiredText: PropTypes.string,
fileDropHeader: PropTypes.string,
/** Max file size in bytes. Defaults to `Infinity`. */
fileDropLabel: PropTypes.string,
fileDropLabelPlural: PropTypes.string,
fileDropLabelSingular: PropTypes.string,
/** The file tab label. Defaults to "File" */
fileTabLabel: PropTypes.string,
filesToUploadText: PropTypes.string,
filesToUploadTextPlural: PropTypes.string,
hideImport: PropTypes.bool,
importDescription: PropTypes.string,
initialFiles: PropTypes.array,
invalidExtensionText: PropTypes.string,
invalidFileNameText: PropTypes.string,
invalidUrlText: PropTypes.string,
maxFileSize: PropTypes.number,
maxFileSizeMessage: PropTypes.string,
multiple: PropTypes.bool,
mustBeExtensionTextPlural: PropTypes.string,
mustBeExtensionTextSingular: PropTypes.string,
onFileAdded: PropTypes.func,
onFileRemoved: PropTypes.func,
/** Called when the entire form is submitted. See README for examples. */
onImport: PropTypes.func,
onValidateUrl: PropTypes.func,
/** Defaults to `true`. Set to false to hide/close the modal. */
open: PropTypes.bool,
singleFileLabel: PropTypes.string,
sync: PropTypes.bool,
uploadDescription: PropTypes.string,
urlInputHeader: PropTypes.string,
urlInputLabel: PropTypes.string,
/** The file tab label. Defaults to "URL" */
urlTabLabel: PropTypes.string,
/** Defaults to `['*']`. Specify valid file extensions. */
validExtensions: PropTypes.arrayOf(PropTypes.string).isRequired,
verbLabel: PropTypes.string
};
IdeImporting.defaultProps = {
uploadDescription: 'Use the inputs below to select file(s) to be uploaded.',
importDescription: 'Use the inputs below to select file(s) to be imported.',
open: true,
sync: false,
headingPlural: 'Select Files to import',
headingSingular: 'Select a File import',
fileTabLabel: 'File',
hideImport: false,
urlTabLabel: 'URL',
invalidFileNameText: 'You must provide a valid file name.',
validExtensions: ['*'],
multiple: true,
fileDropLabelSingular: 'Drag and drop a single file here or click to import',
fileDropLabelPlural: 'Drag and drop files here or click to import',
filenameRequiredText: 'A filename is required.',
urlInputLabel: '',
invalidUrlText: 'Enter a valid URL',
maxFileSize: Infinity,
maxFileSizeSubject: 'File size exceeds limit',
maxFileSizeMessage: 'File is larger than the max file size.',
addUrlBttonLabel: 'Add File',
extensionIsRequiredText: 'File must have a valid extension.',
extensionIsInvalidText: 'Extension is not valid.',
errorTextSingular: 'Failed to import file.',
errorTextPlural: 'Failed to import files.',
successTextSingular: 'Your file has been imported.',
successTextPlural: 'Your files have been imported.',
extensionRequired: true,
autoCloseDelay: 2,
enableFileDrop: true,
enableUrlInput: true,
invalidFileText: 'Invalid File',
initialFiles: [],
mustBeExtensionTextSingular: 'Must be a $EXT file.',
mustBeExtensionTextPlural: 'Must be one of: $EXT.',
allowInvalidFilenameInUrl: false,
defaultUncaughtErrorSubject: 'Import Failed',
defaultUncaughtErrorBody: 'Failed to import file.',
filesToUploadTextPlural: 'Files to import',
enableUpload: true,
allowValidFileEditing: false,
fileDropHeader: 'Add by File',
urlInputHeader: 'Add by URL',
singleFileLabel: 'File'
};