import React from 'react'; import _ from 'lodash'; import FormStyledButton from '../widgets/FormStyledButton'; import styled from 'styled-components'; import { FormReactSelect, FormConnectionSelect, FormDatabaseSelect, FormTablesSelect, FormSchemaSelect, FormArchiveFolderSelect, FormArchiveFilesSelect, } from '../utility/forms'; import { useArchiveFiles, useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders'; import TableControl, { TableColumn } from '../utility/TableControl'; import { TextField, SelectField, CheckboxField } from '../utility/inputs'; import { createPreviewReader, getActionOptions, getTargetName } from './createImpExpScript'; import getElectron from '../utility/getElectron'; import ErrorInfo from '../widgets/ErrorInfo'; import getAsArray from '../utility/getAsArray'; import LoadingInfo from '../widgets/LoadingInfo'; import SqlEditor from '../sqleditor/SqlEditor'; import { useUploadsProvider } from '../utility/UploadsProvider'; import { FontIcon } from '../icons'; import useTheme from '../theme/useTheme'; import { findFileFormat, getFileFormatDirections } from '../utility/fileformats'; import FormArgumentList from '../utility/FormArgumentList'; import useExtensions from '../utility/useExtensions'; import UploadButton from '../utility/UploadButton'; import useShowModal from '../modals/showModal'; import ChangeDownloadUrlModal from '../modals/ChangeDownloadUrlModal'; import { useForm } from '../utility/FormProvider'; const Container = styled.div` // max-height: 50vh; // overflow-y: scroll; flex: 1; `; const Wrapper = styled.div` display: flex; `; const SourceListWrapper = styled.div` margin: 10px; `; const Column = styled.div` margin: 10px; flex: 1; `; const Label = styled.div` margin: 5px; margin-top: 15px; color: ${props => props.theme.modal_font2}; `; const SourceNameWrapper = styled.div` display: flex; justify-content: space-between; `; const SourceNameButtons = styled.div` display: flex; `; const IconButtonWrapper = styled.div` &:hover { background-color: ${props => props.theme.modal_background2}; } cursor: pointer; color: ${props => props.theme.modal_font_blue[7]}; margin-left: 5px; `; const SqlWrapper = styled.div` position: relative; height: 100px; width: 20vw; `; const DragWrapper = styled.div` padding: 10px; background: ${props => props.theme.modal_background2}; `; const ArrowWrapper = styled.div` font-size: 30px; color: ${props => props.theme.modal_font_blue[7]}; align-self: center; `; const Title = styled.div` font-size: 20px; text-align: center; margin: 10px 0px; `; const ButtonsLine = styled.div` display: flex; `; function getFileFilters(extensions, storageType) { const res = []; const format = findFileFormat(extensions, storageType); if (format) res.push({ name: format.name, extensions: [format.extension] }); res.push({ name: 'All Files', extensions: ['*'] }); return res; } async function addFileToSourceListDefault({ fileName, shortName, isDownload }, newSources, newValues) { const sourceName = shortName; newSources.push(sourceName); newValues[`sourceFile_${sourceName}`] = { fileName, isDownload, }; } async function addFilesToSourceList(extensions, files, values, setValues, preferedStorageType, setPreviewSource) { const newSources = []; const newValues = {}; const storage = preferedStorageType || values.sourceStorageType; for (const file of getAsArray(files)) { const format = findFileFormat(extensions, storage); if (format) { await (format.addFileToSourceList || addFileToSourceListDefault)(file, newSources, newValues); } } newValues['sourceList'] = [...(values.sourceList || []).filter(x => !newSources.includes(x)), ...newSources]; if (preferedStorageType && preferedStorageType != values.sourceStorageType) { newValues['sourceStorageType'] = preferedStorageType; } setValues({ ...values, ...newValues, }); if (setPreviewSource && newSources.length == 1) { setPreviewSource(newSources[0]); } } function ElectronFilesInput() { const { values, setValues } = useForm(); const electron = getElectron(); const [isLoading, setIsLoading] = React.useState(false); const extensions = useExtensions(); const handleClick = async () => { const files = electron.remote.dialog.showOpenDialogSync(electron.remote.getCurrentWindow(), { properties: ['openFile', 'multiSelections'], filters: getFileFilters(extensions, values.sourceStorageType), }); if (files) { const path = window.require('path'); try { setIsLoading(true); await addFilesToSourceList( extensions, files.map(full => ({ fileName: full, shortName: path.parse(full).name, })), values, setValues ); } finally { setIsLoading(false); } } }; return ( <> {isLoading && } ); } function extractUrlName(url, values) { const match = url.match(/\/([^/]+)($|\?)/); if (match) { const res = match[1]; if (res.includes('.')) { return res.slice(0, res.indexOf('.')); } return res; } return `url${values && values.sourceList ? values.sourceList.length + 1 : '1'}`; } function FilesInput({ setPreviewSource = undefined }) { const theme = useTheme(); const electron = getElectron(); const showModal = useShowModal(); const { values, setValues } = useForm(); const extensions = useExtensions(); const doAddUrl = url => { addFilesToSourceList( extensions, [ { fileName: url, shortName: extractUrlName(url, values), isDownload: true, }, ], values, setValues, null, setPreviewSource ); }; const handleAddUrl = () => showModal(modalState => ); return ( <> {electron ? : } Drag & drop imported files here ); } function SourceTargetConfig({ direction, storageTypeField, connectionIdField, databaseNameField, archiveFolderField, schemaNameField, tablesField = undefined, engine = undefined, setPreviewSource = undefined, }) { const extensions = useExtensions(); const theme = useTheme(); const { values, setFieldValue } = useForm(); const types = values[storageTypeField] == 'jsldata' ? [{ value: 'jsldata', label: 'Query result data', directions: ['source'] }] : [ { value: 'database', label: 'Database', directions: ['source', 'target'] }, ...extensions.fileFormats.map(format => ({ value: format.storageType, label: `${format.name} files(s)`, directions: getFileFormatDirections(format), })), { value: 'query', label: 'SQL Query', directions: ['source'] }, { value: 'archive', label: 'Archive', directions: ['source', 'target'] }, ]; const storageType = values[storageTypeField]; const dbinfo = useDatabaseInfo({ conid: values[connectionIdField], database: values[databaseNameField] }); const archiveFiles = useArchiveFiles({ folder: values[archiveFolderField] }); const format = findFileFormat(extensions, storageType); return ( {direction == 'source' && ( <FontIcon icon="icon import" /> Source configuration )} {direction == 'target' && ( <FontIcon icon="icon export" /> Target configuration )} x.directions.includes(direction))} name={storageTypeField} /> {(storageType == 'database' || storageType == 'query') && ( <> )} {storageType == 'database' && ( <> {tablesField && ( <>
setFieldValue( 'sourceList', _.uniq([...(values.sourceList || []), ...(dbinfo && dbinfo.tables.map(x => x.pureName))]) ) } /> setFieldValue( 'sourceList', _.uniq([...(values.sourceList || []), ...(dbinfo && dbinfo.views.map(x => x.pureName))]) ) } /> setFieldValue('sourceList', [])} />
)} )} {storageType == 'query' && ( <> setFieldValue('sourceSql', value)} engine={engine} focusOnCreate /> )} {storageType == 'archive' && ( <> )} {storageType == 'archive' && direction == 'source' && ( <>
setFieldValue( 'sourceList', _.uniq([...(values.sourceList || []), ...(archiveFiles && archiveFiles.map(x => x.name))]) ) } /> setFieldValue('sourceList', [])} />
)} {!!format && direction == 'source' && } {format && format.args && ( !arg.direction || arg.direction == direction)} namePrefix={`${direction}_${format.storageType}_`} /> )}
); } function SourceName({ name }) { const { values, setFieldValue } = useForm(); const theme = useTheme(); const showModal = useShowModal(); const obj = values[`sourceFile_${name}`]; const handleDelete = () => { setFieldValue( 'sourceList', values.sourceList.filter(x => x != name) ); }; const doChangeUrl = url => { setFieldValue(`sourceFile_${name}`, { fileName: url, isDownload: true }); }; const handleChangeUrl = () => { showModal(modalState => ( )); }; return (
{name}
{obj && !!obj.isDownload && ( )}
); } export default function ImportExportConfigurator({ uploadedFile = undefined, openedFile = undefined, onChangePreview = undefined, }) { const { values, setFieldValue, setValues } = useForm(); const targetDbinfo = useDatabaseInfo({ conid: values.targetConnectionId, database: values.targetDatabaseName }); const sourceConnectionInfo = useConnectionInfo({ conid: values.sourceConnectionId }); const { engine: sourceEngine } = sourceConnectionInfo || {}; const { sourceList } = values; const { setUploadListener } = useUploadsProvider(); const theme = useTheme(); const [previewSource, setPreviewSource] = React.useState(null); const extensions = useExtensions(); const handleUpload = React.useCallback( file => { addFilesToSourceList( extensions, [ { fileName: file.filePath, shortName: file.shortName, }, ], values, setValues, !sourceList || sourceList.length == 0 ? file.storageType : null, setPreviewSource ); // setFieldValue('sourceList', [...(sourceList || []), file.originalName]); }, [extensions, setFieldValue, sourceList, values] ); React.useEffect(() => { setUploadListener(() => handleUpload); return () => { setUploadListener(null); }; }, [handleUpload]); React.useEffect(() => { if (uploadedFile) { handleUpload(uploadedFile); } if (openedFile) { addFilesToSourceList( extensions, [ { fileName: openedFile.filePath, shortName: openedFile.shortName, }, ], values, setValues, !sourceList || sourceList.length == 0 ? openedFile.storageType : null, setPreviewSource ); } }, []); const supportsPreview = !!findFileFormat(extensions, values.sourceStorageType) || values.sourceStorageType == 'archive'; const previewFileName = previewSource && values[`sourceFile_${previewSource}`] && values[`sourceFile_${previewSource}`].fileName; const handleChangePreviewSource = async () => { if (previewSource && supportsPreview) { const reader = await createPreviewReader(extensions, values, previewSource); if (onChangePreview) onChangePreview(reader); } else { onChangePreview(null); } }; React.useEffect(() => { handleChangePreviewSource(); }, [previewSource, supportsPreview, previewFileName]); const oldValues = React.useRef({}); React.useEffect(() => { const changed = _.pickBy( values, (v, k) => k.startsWith(`source_${values.sourceStorageType}_`) && oldValues.current[k] != v ); if (!_.isEmpty(changed)) { handleChangePreviewSource(); } oldValues.current = values; }, [values]); return ( <FontIcon icon="icon tables" /> Map source tables/files } /> ( setFieldValue(`actionType_${row}`, e.target.value)} /> )} /> ( setFieldValue(`targetName_${row}`, e.target.value)} /> )} /> supportsPreview ? ( { if (e.target.checked) setPreviewSource(row); else setPreviewSource(null); }} /> ) : null } /> {(sourceList || []).length == 0 && } ); }