diff --git a/packages/web/package.json b/packages/web/package.json
index 7cf6a3472..9a453c0e0 100644
--- a/packages/web/package.json
+++ b/packages/web/package.json
@@ -21,6 +21,7 @@
"react-dom": "^16.12.0",
"react-modal": "^3.11.1",
"react-scripts": "3.3.0",
+ "react-select": "^3.1.0",
"resize-observer-polyfill": "^1.5.1",
"socket.io-client": "^2.3.0",
"sql-formatter": "^2.3.3",
diff --git a/packages/web/src/datagrid/DataGridContextMenu.js b/packages/web/src/datagrid/DataGridContextMenu.js
index 7ff2b39de..90a33f7b5 100644
--- a/packages/web/src/datagrid/DataGridContextMenu.js
+++ b/packages/web/src/datagrid/DataGridContextMenu.js
@@ -8,6 +8,7 @@ export default function DataGridContextMenu({
insertNewRow,
setNull,
reload,
+ exportGrid,
}) {
return (
<>
@@ -31,6 +32,9 @@ export default function DataGridContextMenu({
Set NULL
+
+ Export
+
>
);
}
diff --git a/packages/web/src/datagrid/DataGridCore.js b/packages/web/src/datagrid/DataGridCore.js
index 1a990de6e..bf54a8da0 100644
--- a/packages/web/src/datagrid/DataGridCore.js
+++ b/packages/web/src/datagrid/DataGridCore.js
@@ -42,6 +42,7 @@ import LoadingInfo from '../widgets/LoadingInfo';
import ErrorInfo from '../widgets/ErrorInfo';
import showModal from '../modals/showModal';
import ErrorMessageModal from '../modals/ErrorMessageModal';
+import ImportExportModal from '../modals/ImportExportModal';
const GridContainer = styled.div`
position: absolute;
@@ -537,6 +538,7 @@ export default function DataGridCore(props) {
insertNewRow={insertNewRow}
reload={() => display.reload()}
setNull={setNull}
+ exportGrid={exportGrid}
/>
);
};
@@ -591,6 +593,10 @@ export default function DataGridCore(props) {
copyToClipboard();
}
+ function exportGrid() {
+ showModal((modalState) => );
+ }
+
function setCellValue(chs, cell, value) {
return setChangeSetValue(
chs,
diff --git a/packages/web/src/impexp/ImportExportConfigurator.js b/packages/web/src/impexp/ImportExportConfigurator.js
new file mode 100644
index 000000000..ca53e4d3a
--- /dev/null
+++ b/packages/web/src/impexp/ImportExportConfigurator.js
@@ -0,0 +1,110 @@
+import React from 'react';
+import FormStyledButton from '../widgets/FormStyledButton';
+import { Formik, Form, useFormik, useFormikContext } from 'formik';
+import styled from 'styled-components';
+import Select from 'react-select';
+import { FontIcon } from '../icons';
+import { FormButtonRow, FormSubmit, FormReactSelect, FormConnectionSelect, FormDatabaseSelect } from '../utility/forms';
+import { useConnectionList, useDatabaseList } from '../utility/metadataLoaders';
+
+const Wrapper = styled.div`
+ display: flex;
+`;
+
+const Column = styled.div`
+ margin: 10px;
+ flex: 1;
+`;
+
+const StyledSelect = styled(Select)`
+ // min-width: 350px;
+`;
+
+const OptionsWrapper = styled.div`
+ margin-left: 10px;
+`;
+
+const Label = styled.div`
+ margin: 5px;
+ margin-top: 15px;
+ color: #777;
+`;
+
+function DatabaseSelector() {
+ const connections = useConnectionList();
+ const connectionOptions = React.useMemo(
+ () =>
+ (connections || []).map((conn) => ({
+ value: conn._id,
+ label: conn.displayName || conn.server,
+ })),
+ [connections]
+ );
+
+ // const databases = useDatabaseList({ conid: _id });
+
+ return (
+ <>
+
+
+ >
+ );
+}
+
+function SourceTargetConfig({
+ isSource = false,
+ isTarget = false,
+ storageTypeField,
+ connectionIdField,
+ databaseNameField,
+}) {
+ const types = [
+ { value: 'database', label: 'Database' },
+ { value: 'csv', label: 'CSV file(s)' },
+ { value: 'json', label: 'JSON file(s)' },
+ ];
+ const { values } = useFormikContext();
+ return (
+
+ {isSource && }
+ {isTarget && }
+
+ {values[storageTypeField] == 'database' && (
+ <>
+
+
+
+
+ >
+ )}
+
+ );
+}
+
+export default function ImportExportConfigurator() {
+ return (
+
+
+
+ );
+}
diff --git a/packages/web/src/modals/ImportExportModal.js b/packages/web/src/modals/ImportExportModal.js
new file mode 100644
index 000000000..6d2f49d5d
--- /dev/null
+++ b/packages/web/src/modals/ImportExportModal.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import ModalBase from './ModalBase';
+import FormStyledButton from '../widgets/FormStyledButton';
+import styled from 'styled-components';
+import Select from 'react-select';
+import { FontIcon } from '../icons';
+import { FormButtonRow, FormSubmit } from '../utility/forms';
+import ModalHeader from './ModalHeader';
+import ModalFooter from './ModalFooter';
+import ModalContent from './ModalContent';
+import { useConnectionList, useDatabaseList } from '../utility/metadataLoaders';
+import ImportExportConfigurator from '../impexp/ImportExportConfigurator';
+
+export default function ImportExportModal({ modalState }) {
+ return (
+
+ Import/Export
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/web/src/utility/forms.js b/packages/web/src/utility/forms.js
index 8f22f6a73..ba3f3e743 100644
--- a/packages/web/src/utility/forms.js
+++ b/packages/web/src/utility/forms.js
@@ -1,8 +1,11 @@
import React from 'react';
import styled from 'styled-components';
+import Select from 'react-select';
import { TextField, SelectField } from './inputs';
import { Field, useFormikContext } from 'formik';
import FormStyledButton from '../widgets/FormStyledButton';
+import { useConnectionList, useDatabaseList } from './metadataLoaders';
+import useSocket from './SocketProvider';
export const FormRow = styled.div`
display: flex;
@@ -80,3 +83,46 @@ export function FormRadioGroupItem({ name, text, value }) {
);
}
+
+export function FormReactSelect({ options, name }) {
+ const { setFieldValue, values } = useFormikContext();
+ return (
+