UNPKG

@grafana/ui

Version:
258 lines (255 loc) • 9.25 kB
import { jsx, jsxs } from 'react/jsx-runtime'; import { cx, css } from '@emotion/css'; import { isString, uniqueId } from 'lodash'; import { useState, useCallback } from 'react'; import { useDropzone, ErrorCode } from 'react-dropzone'; import { getValueFormat, formattedValueToString } from '@grafana/data'; import { t, Trans } from '@grafana/i18n'; import { useTheme2 } from '../../themes/ThemeContext.mjs'; import { Alert } from '../Alert/Alert.mjs'; import { Icon } from '../Icon/Icon.mjs'; import { FileListItem } from './FileListItem.mjs'; function FileDropzone({ options, children, readAs, onLoad, fileListRenderer, onFileRemove }) { const [files, setFiles] = useState([]); const [fileErrors, setErrorMessages] = useState([]); const formattedSize = getValueFormat("decbytes")((options == null ? void 0 : options.maxSize) ? options == null ? void 0 : options.maxSize : 0); const setFileProperty = useCallback( (customFile, action) => { setFiles((oldFiles) => { return oldFiles.map((oldFile) => { if (oldFile.id === customFile.id) { action(oldFile); return oldFile; } return oldFile; }); }); }, [] ); const onDrop = useCallback( (acceptedFiles, rejectedFiles, event) => { let customFiles = acceptedFiles.map(mapToCustomFile); if ((options == null ? void 0 : options.multiple) === false) { setFiles(customFiles); } else { setFiles((oldFiles) => [...oldFiles, ...customFiles]); } setErrors(rejectedFiles); if (options == null ? void 0 : options.onDrop) { options.onDrop(acceptedFiles, rejectedFiles, event); } else { for (const customFile of customFiles) { const reader = new FileReader(); const read = () => { if (readAs) { reader[readAs](customFile.file); } else { reader.readAsText(customFile.file); } }; setFileProperty(customFile, (fileToModify) => { fileToModify.abortUpload = () => { reader.abort(); }; fileToModify.retryUpload = () => { setFileProperty(customFile, (fileToModify2) => { fileToModify2.error = null; fileToModify2.progress = void 0; }); read(); }; }); reader.onabort = () => { setFileProperty(customFile, (fileToModify) => { fileToModify.error = new DOMException("Aborted"); }); }; reader.onprogress = (event2) => { setFileProperty(customFile, (fileToModify) => { fileToModify.progress = event2.loaded; }); }; reader.onload = () => { onLoad == null ? void 0 : onLoad(reader.result); }; reader.onerror = () => { setFileProperty(customFile, (fileToModify) => { fileToModify.error = reader.error; }); }; read(); } } }, [onLoad, options, readAs, setFileProperty] ); const removeFile = (file) => { const newFiles = files.filter((f) => file.id !== f.id); setFiles(newFiles); onFileRemove == null ? void 0 : onFileRemove(file); }; const { getRootProps, getInputProps, isDragActive } = useDropzone({ ...options, useFsAccessApi: false, onDrop, accept: transformAcceptToNewFormat(options == null ? void 0 : options.accept) }); const theme = useTheme2(); const styles = getStyles(theme, isDragActive); const fileList = files.map((file) => { if (fileListRenderer) { return fileListRenderer(file, removeFile); } return /* @__PURE__ */ jsx(FileListItem, { file, removeFile }, file.id); }); const setErrors = (rejectedFiles) => { let errors = []; rejectedFiles.map((rejectedFile) => { rejectedFile.errors.map((newError) => { if (errors.findIndex((presentError) => { return presentError.code === newError.code && presentError.message === newError.message; }) === -1) { errors.push(newError); } }); }); setErrorMessages(errors); }; const renderErrorMessages = (errors) => { const size = formattedValueToString(formattedSize); return /* @__PURE__ */ jsx("div", { className: styles.errorAlert, children: /* @__PURE__ */ jsx( Alert, { title: t("grafana-ui.file-dropzone.error-title", "Upload failed"), severity: "error", onRemove: clearAlert, children: errors.map((error) => { switch (error.code) { case ErrorCode.FileTooLarge: return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(Trans, { i18nKey: "grafana-ui.file-dropzone.file-too-large", children: [ "File is larger than ", { size } ] }) }, error.message + error.code); default: return /* @__PURE__ */ jsx("div", { children: error.message }, error.message + error.code); } }) } ) }); }; const clearAlert = () => { setErrorMessages([]); }; return /* @__PURE__ */ jsxs("div", { className: styles.container, children: [ /* @__PURE__ */ jsxs("div", { "data-testid": "dropzone", ...getRootProps({ className: styles.dropzone }), children: [ /* @__PURE__ */ jsx("input", { ...getInputProps() }), children != null ? children : /* @__PURE__ */ jsx(FileDropzoneDefaultChildren, { primaryText: getPrimaryText(files, options) }) ] }), fileErrors.length > 0 && renderErrorMessages(fileErrors), /* @__PURE__ */ jsxs("small", { className: cx(styles.small, styles.acceptContainer), children: [ (options == null ? void 0 : options.maxSize) && `Max file size: ${formattedValueToString(formattedSize)}`, (options == null ? void 0 : options.maxSize) && (options == null ? void 0 : options.accept) && /* @__PURE__ */ jsx("span", { className: styles.acceptSeparator, children: "|" }), (options == null ? void 0 : options.accept) && getAcceptedFileTypeText(options.accept) ] }), fileList ] }); } function getMimeTypeByExtension(ext) { if (["txt", "json", "csv", "xls", "yml"].some((e) => ext.match(e))) { return "text/plain"; } return "application/octet-stream"; } function transformAcceptToNewFormat(accept) { if (isString(accept)) { return { [getMimeTypeByExtension(accept)]: [accept] }; } if (Array.isArray(accept)) { return accept.reduce((prev, current) => { const mime = getMimeTypeByExtension(current); prev[mime] = prev[mime] ? [...prev[mime], current] : [current]; return prev; }, {}); } return accept; } function FileDropzoneDefaultChildren({ primaryText = "Drop file here or click to upload", secondaryText = "" }) { const theme = useTheme2(); const styles = getStyles(theme); return /* @__PURE__ */ jsxs("div", { className: cx(styles.defaultDropZone), "data-testid": "file-drop-zone-default-children", children: [ /* @__PURE__ */ jsx(Icon, { className: cx(styles.icon), name: "upload", size: "xl" }), /* @__PURE__ */ jsx("h6", { className: cx(styles.primaryText), children: primaryText }), /* @__PURE__ */ jsx("small", { className: styles.small, children: secondaryText }) ] }); } function getPrimaryText(files, options) { if ((options == null ? void 0 : options.multiple) === void 0 || (options == null ? void 0 : options.multiple)) { return "Upload file"; } return files.length ? "Replace file" : "Upload file"; } function getAcceptedFileTypeText(accept) { if (isString(accept)) { return `Accepted file type: ${accept}`; } if (Array.isArray(accept)) { return `Accepted file types: ${accept.join(", ")}`; } return `Accepted file types: ${Object.values(accept).flat().join(", ")}`; } function mapToCustomFile(file) { return { id: uniqueId("file"), file, error: null }; } function getStyles(theme, isDragActive) { return { container: css({ display: "flex", flexDirection: "column", width: "100%", padding: theme.spacing(2), borderRadius: theme.shape.radius.default, border: `1px dashed ${theme.colors.border.strong}`, backgroundColor: isDragActive ? theme.colors.background.secondary : theme.colors.background.primary, cursor: "pointer", alignItems: "center", justifyContent: "center" }), dropzone: css({ height: "100%", width: "100%", display: "flex", flexDirection: "column" }), defaultDropZone: css({ textAlign: "center" }), icon: css({ marginBottom: theme.spacing(1) }), primaryText: css({ marginBottom: theme.spacing(1) }), acceptContainer: css({ textAlign: "center", margin: 0 }), acceptSeparator: css({ margin: `0 ${theme.spacing(1)}` }), small: css({ color: theme.colors.text.secondary }), errorAlert: css({ paddingTop: "10px" }) }; } export { FileDropzone, FileDropzoneDefaultChildren, getMimeTypeByExtension, transformAcceptToNewFormat }; //# sourceMappingURL=FileDropzone.mjs.map