diff --git a/packages/web/src/App.js b/packages/web/src/App.js
index b8bd715de..0497767a6 100644
--- a/packages/web/src/App.js
+++ b/packages/web/src/App.js
@@ -28,18 +28,18 @@ function App() {
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
diff --git a/packages/web/src/DragAndDropFileTarget.js b/packages/web/src/DragAndDropFileTarget.js
index 41e0211f0..85ece2ec1 100644
--- a/packages/web/src/DragAndDropFileTarget.js
+++ b/packages/web/src/DragAndDropFileTarget.js
@@ -1,8 +1,8 @@
import React from 'react';
import styled from 'styled-components';
-import { fileformats } from './fileformats';
import { FontIcon } from './icons';
import useTheme from './theme/useTheme';
+import useExtensions from './utility/useExtensions';
const TargetStyled = styled.div`
position: fixed;
@@ -40,6 +40,7 @@ const TitleWrapper = styled.div`
export default function DragAndDropFileTarget({ isDragActive, inputProps }) {
const theme = useTheme();
+ const { fileFormats } = useExtensions();
return (
!!isDragActive && (
@@ -50,7 +51,7 @@ export default function DragAndDropFileTarget({ isDragActive, inputProps }) {
Drop the files to upload to DbGate
Supported file types:{' '}
- {fileformats
+ {fileFormats
.filter((x) => x.readerFunc)
.map((x) => x.name)
.join(', ')}
diff --git a/packages/web/src/appobj/databaseAppObject.js b/packages/web/src/appobj/databaseAppObject.js
index ae4598f49..7e3db8f17 100644
--- a/packages/web/src/appobj/databaseAppObject.js
+++ b/packages/web/src/appobj/databaseAppObject.js
@@ -3,9 +3,9 @@ import _ from 'lodash';
import { DropDownMenuItem } from '../modals/DropDownMenu';
import { openNewTab } from '../utility/common';
import ImportExportModal from '../modals/ImportExportModal';
-import { defaultFileFormat } from '../fileformats';
+import { getDefaultFileFormat } from '../utility/fileformats';
-function Menu({ data, setOpenedTabs, showModal }) {
+function Menu({ data, setOpenedTabs, showModal, extensions }) {
const { connection, name } = data;
const tooltip = `${connection.displayName || connection.server}\n${name}`;
@@ -27,7 +27,7 @@ function Menu({ data, setOpenedTabs, showModal }) {
{
- const resp = await axios.get(`files/analyse-excel?filePath=${encodeURIComponent(file.full)}`);
- const sheetNames = resp.data;
- for (const sheetName of sheetNames) {
- newSources.push(sheetName);
- newValues[`sourceFile_${sheetName}`] = {
- fileName: file.full,
- sheetName,
- };
- }
- },
-
- args: [
- {
- type: 'checkbox',
- name: 'singleFile',
- label: 'Create single file',
- direction: 'target',
- },
- ],
-
- getDefaultOutputName: (sourceName, values) => {
- if (values.target_excel_singleFile) {
- return sourceName;
- }
- return null;
- },
-
- getOutputParams: (sourceName, values) => {
- if (values.target_excel_singleFile) {
- return {
- sheetName: values[`targetName_${sourceName}`] || sourceName,
- fileName:'data.xlsx'
- };
- }
- return null;
- },
-};
-
-export default excelFormat;
diff --git a/packages/web/src/fileformats/index.ts b/packages/web/src/fileformats/index.ts
deleted file mode 100644
index 2824490fe..000000000
--- a/packages/web/src/fileformats/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import csv from './csv';
-import jsonl from './jsonl';
-import excel from './excel';
-import { FileFormatDefinition } from './types';
-
-export const fileformats = [csv, jsonl, excel];
-
-export function findFileFormat(storageType): FileFormatDefinition {
- return fileformats.find((x) => x.storageType == storageType);
-}
-
-export function getFileFormatDirections(format: FileFormatDefinition) {
- if (!format) return [];
- const res = [];
- if (format.readerFunc) res.push('source');
- if (format.writerFunc) res.push('target');
- return res;
-}
-
-export const defaultFileFormat = csv;
\ No newline at end of file
diff --git a/packages/web/src/fileformats/jsonl.ts b/packages/web/src/fileformats/jsonl.ts
deleted file mode 100644
index 944f5fef7..000000000
--- a/packages/web/src/fileformats/jsonl.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { FileFormatDefinition } from './types';
-
-const jsonlFormat: FileFormatDefinition = {
- storageType: 'jsonl',
- extension: 'jsonl',
- name: 'JSON lines',
- readerFunc: 'jsonLinesReader',
- writerFunc: 'jsonLinesWriter',
-};
-
-export default jsonlFormat;
diff --git a/packages/web/src/fileformats/types.ts b/packages/web/src/fileformats/types.ts
deleted file mode 100644
index c669c63fd..000000000
--- a/packages/web/src/fileformats/types.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export interface FileFormatDefinition {
- storageType: string;
- extension: string;
- name: string;
- readerFunc?: string;
- writerFunc?: string;
- args?: any[];
- addFilesToSourceList?: (
- file: {
- full: string;
- },
- newSources: string[],
- newValues: {
- [key: string]: any;
- }
- ) => void;
- getDefaultOutputName?: (sourceName, values) => string;
- getOutputParams?: (sourceName, values) => any;
-}
diff --git a/packages/web/src/impexp/ImportExportConfigurator.js b/packages/web/src/impexp/ImportExportConfigurator.js
index ac137b503..6913ef286 100644
--- a/packages/web/src/impexp/ImportExportConfigurator.js
+++ b/packages/web/src/impexp/ImportExportConfigurator.js
@@ -12,10 +12,10 @@ import {
FormArchiveFolderSelect,
FormArchiveFilesSelect,
} from '../utility/forms';
-import { useArchiveFiles, useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
+import { useArchiveFiles, useConnectionInfo, useDatabaseInfo, useInstalledPlugins } from '../utility/metadataLoaders';
import TableControl, { TableColumn } from '../utility/TableControl';
import { TextField, SelectField, CheckboxField } from '../utility/inputs';
-import { createPreviewReader, getActionOptions, getTargetName, isFileStorage } from './createImpExpScript';
+import { createPreviewReader, getActionOptions, getTargetName } from './createImpExpScript';
import getElectron from '../utility/getElectron';
import ErrorInfo from '../widgets/ErrorInfo';
import getAsArray from '../utility/getAsArray';
@@ -25,8 +25,9 @@ import SqlEditor from '../sqleditor/SqlEditor';
import { useUploadsProvider } from '../utility/UploadsProvider';
import { FontIcon } from '../icons';
import useTheme from '../theme/useTheme';
-import { fileformats, findFileFormat, getFileFormatDirections } from '../fileformats';
+import { findFileFormat, getFileFormatDirections } from '../utility/fileformats';
import FormArgumentList from '../utility/FormArgumentList';
+import useExtensions from '../utility/useExtensions';
const Container = styled.div`
// max-height: 50vh;
@@ -89,9 +90,9 @@ const Title = styled.div`
margin: 10px 0px;
`;
-function getFileFilters(storageType) {
+function getFileFilters(extensions, storageType) {
const res = [];
- const format = findFileFormat(storageType);
+ const format = findFileFormat(extensions, storageType);
if (format) res.push({ name: format.name, extensions: [format.extension] });
res.push({ name: 'All Files', extensions: ['*'] });
return res;
@@ -105,12 +106,12 @@ async function addFilesToSourceListDefault(file, newSources, newValues) {
};
}
-async function addFilesToSourceList(files, values, setValues, preferedStorageType, setPreviewSource) {
+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(storage);
+ const format = findFileFormat(extensions, storage);
if (format) {
await (format.addFilesToSourceList || addFilesToSourceListDefault)(file, newSources, newValues);
}
@@ -132,17 +133,19 @@ function ElectronFilesInput() {
const { values, setValues } = useFormikContext();
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(values.sourceStorageType),
+ filters: getFileFilters(extensions, values.sourceStorageType),
});
if (files) {
const path = window.require('path');
try {
setIsLoading(true);
await addFilesToSourceList(
+ extensions,
files.map((full) => ({
full,
...path.parse(full),
@@ -183,6 +186,7 @@ function SourceTargetConfig({
tablesField = undefined,
engine = undefined,
}) {
+ const extensions = useExtensions();
const theme = useTheme();
const { values, setFieldValue } = useFormikContext();
const types =
@@ -190,7 +194,7 @@ function SourceTargetConfig({
? [{ value: 'jsldata', label: 'Query result data', directions: ['source'] }]
: [
{ value: 'database', label: 'Database', directions: ['source', 'target'] },
- ...fileformats.map((format) => ({
+ ...extensions.fileFormats.map((format) => ({
value: format.storageType,
label: `${format.name} files(s)`,
directions: getFileFormatDirections(format),
@@ -201,7 +205,7 @@ function SourceTargetConfig({
const storageType = values[storageTypeField];
const dbinfo = useDatabaseInfo({ conid: values[connectionIdField], database: values[databaseNameField] });
const archiveFiles = useArchiveFiles({ folder: values[archiveFolderField] });
- const format = findFileFormat(storageType);
+ const format = findFileFormat(extensions, storageType);
return (
{direction == 'source' && (
@@ -348,10 +352,17 @@ export default function ImportExportConfigurator({ uploadedFile = undefined, onC
const { setUploadListener } = useUploadsProvider();
const theme = useTheme();
const [previewSource, setPreviewSource] = React.useState(null);
+ const extensions = useExtensions();
+
+ console.log('ImportExportConfigurator', extensions);
+ const installed = useInstalledPlugins();
+ console.log('installed', installed);
const handleUpload = React.useCallback(
(file) => {
+ console.log('UPLOAD', extensions);
addFilesToSourceList(
+ extensions,
[
{
full: file.filePath,
@@ -365,7 +376,7 @@ export default function ImportExportConfigurator({ uploadedFile = undefined, onC
);
// setFieldValue('sourceList', [...(sourceList || []), file.originalName]);
},
- [setFieldValue, sourceList, values]
+ [extensions, setFieldValue, sourceList, values]
);
React.useEffect(() => {
@@ -381,11 +392,11 @@ export default function ImportExportConfigurator({ uploadedFile = undefined, onC
}
}, []);
- const supportsPreview = !!findFileFormat(values.sourceStorageType);
+ const supportsPreview = !!findFileFormat(extensions, values.sourceStorageType);
const handleChangePreviewSource = async () => {
if (previewSource && supportsPreview) {
- const reader = await createPreviewReader(values, previewSource);
+ const reader = await createPreviewReader(extensions, values, previewSource);
if (onChangePreview) onChangePreview(reader);
} else {
onChangePreview(null);
@@ -444,8 +455,8 @@ export default function ImportExportConfigurator({ uploadedFile = undefined, onC
header="Action"
formatter={(row) => (
setFieldValue(`actionType_${row}`, e.target.value)}
/>
)}
@@ -455,7 +466,7 @@ export default function ImportExportConfigurator({ uploadedFile = undefined, onC
header="Target"
formatter={(row) => (
setFieldValue(`targetName_${row}`, e.target.value)}
/>
)}
diff --git a/packages/web/src/impexp/createImpExpScript.js b/packages/web/src/impexp/createImpExpScript.js
index feb068550..d5826d4c3 100644
--- a/packages/web/src/impexp/createImpExpScript.js
+++ b/packages/web/src/impexp/createImpExpScript.js
@@ -4,12 +4,12 @@ import getAsArray from '../utility/getAsArray';
import { getConnectionInfo } from '../utility/metadataLoaders';
import engines from 'dbgate-engines';
import { findObjectLike } from 'dbgate-tools';
-import { findFileFormat } from '../fileformats';
+import { findFileFormat } from '../utility/fileformats';
-export function getTargetName(source, values) {
+export function getTargetName(extensions, source, values) {
const key = `targetName_${source}`;
if (values[key]) return values[key];
- const format = findFileFormat(values.targetStorageType);
+ const format = findFileFormat(extensions, values.targetStorageType);
if (format) {
const res = format.getDefaultOutputName ? format.getDefaultOutputName(source, values) : null;
if (res) return res;
@@ -18,10 +18,6 @@ export function getTargetName(source, values) {
return source;
}
-export function isFileStorage(storageType) {
- return !!findFileFormat(storageType);
-}
-
function extractApiParameters(values, direction, format) {
const pairs = (format.args || [])
.filter((arg) => arg.apiName)
@@ -45,7 +41,7 @@ async function getConnection(storageType, conid, database) {
return [null, null];
}
-function getSourceExpr(sourceName, values, sourceConnection, sourceDriver) {
+function getSourceExpr(extensions, sourceName, values, sourceConnection, sourceDriver) {
const { sourceStorageType } = values;
if (sourceStorageType == 'database') {
const fullName = { schemaName: values.sourceSchemaName, pureName: sourceName };
@@ -66,9 +62,9 @@ function getSourceExpr(sourceName, values, sourceConnection, sourceDriver) {
},
];
}
- if (isFileStorage(sourceStorageType)) {
+ if (findFileFormat(extensions, sourceStorageType)) {
const sourceFile = values[`sourceFile_${sourceName}`];
- const format = findFileFormat(sourceStorageType);
+ const format = findFileFormat(extensions, sourceStorageType);
if (format && format.readerFunc) {
return [
format.readerFunc,
@@ -113,9 +109,9 @@ function getFlagsFroAction(action) {
};
}
-function getTargetExpr(sourceName, values, targetConnection, targetDriver) {
+function getTargetExpr(extensions, sourceName, values, targetConnection, targetDriver) {
const { targetStorageType } = values;
- const format = findFileFormat(targetStorageType);
+ const format = findFileFormat(extensions, targetStorageType);
if (format && format.writerFunc) {
const outputParams = format.getOutputParams && format.getOutputParams(sourceName, values);
return [
@@ -124,7 +120,7 @@ function getTargetExpr(sourceName, values, targetConnection, targetDriver) {
...(outputParams
? outputParams
: {
- fileName: getTargetName(sourceName, values),
+ fileName: getTargetName(extensions, sourceName, values),
}),
...extractApiParameters(values, 'target', format),
},
@@ -136,7 +132,7 @@ function getTargetExpr(sourceName, values, targetConnection, targetDriver) {
{
connection: targetConnection,
schemaName: values.targetSchemaName,
- pureName: getTargetName(sourceName, values),
+ pureName: getTargetName(extensions, sourceName, values),
...getFlagsFroAction(values[`actionType_${sourceName}`]),
},
];
@@ -146,7 +142,7 @@ function getTargetExpr(sourceName, values, targetConnection, targetDriver) {
'archiveWriter',
{
folderName: values.targetArchiveFolder,
- fileName: getTargetName(sourceName, values),
+ fileName: getTargetName(extensions, sourceName, values),
},
];
}
@@ -154,7 +150,7 @@ function getTargetExpr(sourceName, values, targetConnection, targetDriver) {
throw new Error(`Unknown target storage type: ${targetStorageType}`);
}
-export default async function createImpExpScript(values, addEditorInfo = true) {
+export default async function createImpExpScript(extensions, values, addEditorInfo = true) {
const script = new ScriptWriter();
const [sourceConnection, sourceDriver] = await getConnection(
@@ -172,11 +168,11 @@ export default async function createImpExpScript(values, addEditorInfo = true) {
for (const sourceName of sourceList) {
const sourceVar = script.allocVariable();
// @ts-ignore
- script.assign(sourceVar, ...getSourceExpr(sourceName, values, sourceConnection, sourceDriver));
+ script.assign(sourceVar, ...getSourceExpr(extensions, sourceName, values, sourceConnection, sourceDriver));
const targetVar = script.allocVariable();
// @ts-ignore
- script.assign(targetVar, ...getTargetExpr(sourceName, values, targetConnection, targetDriver));
+ script.assign(targetVar, ...getTargetExpr(extensions, sourceName, values, targetConnection, targetDriver));
script.copyStream(sourceVar, targetVar);
script.put();
@@ -188,9 +184,9 @@ export default async function createImpExpScript(values, addEditorInfo = true) {
return script.s;
}
-export function getActionOptions(source, values, targetDbinfo) {
+export function getActionOptions(extensions, source, values, targetDbinfo) {
const res = [];
- const targetName = getTargetName(source, values);
+ const targetName = getTargetName(extensions, source, values);
if (values.targetStorageType == 'database') {
let existing = findObjectLike(
{ schemaName: values.targetSchemaName, pureName: targetName },
@@ -225,13 +221,13 @@ export function getActionOptions(source, values, targetDbinfo) {
return res;
}
-export async function createPreviewReader(values, sourceName) {
+export async function createPreviewReader(extensions, values, sourceName) {
const [sourceConnection, sourceDriver] = await getConnection(
values.sourceStorageType,
values.sourceConnectionId,
values.sourceDatabaseName
);
- const [functionName, props] = getSourceExpr(sourceName, values, sourceConnection, sourceDriver);
+ const [functionName, props] = getSourceExpr(extensions, sourceName, values, sourceConnection, sourceDriver);
return {
functionName,
props: {
diff --git a/packages/web/src/modals/ImportExportModal.js b/packages/web/src/modals/ImportExportModal.js
index bd62384d8..4408724aa 100644
--- a/packages/web/src/modals/ImportExportModal.js
+++ b/packages/web/src/modals/ImportExportModal.js
@@ -22,7 +22,8 @@ import useSocket from '../utility/SocketProvider';
import LoadingInfo from '../widgets/LoadingInfo';
import { FontIcon } from '../icons';
import LargeButton from '../widgets/LargeButton';
-import { defaultFileFormat } from '../fileformats';
+import { getDefaultFileFormat } from '../utility/fileformats';
+import useExtensions from '../utility/useExtensions';
const headerHeight = '60px';
const footerHeight = '100px';
@@ -92,9 +93,10 @@ const FooterButtons = styled.div`
function GenerateSctriptButton({ modalState }) {
const setOpenedTabs = useSetOpenedTabs();
const { values } = useFormikContext();
+ const extensions = useExtensions();
const handleGenerateScript = async () => {
- const code = await createImpExpScript(values);
+ const code = await createImpExpScript(extensions, values);
openNewTab(setOpenedTabs, {
title: 'Shell',
icon: 'img shell',
@@ -141,6 +143,7 @@ export default function ImportExportModal({
const refreshArchiveFolderRef = React.useRef(null);
const setArchive = useSetCurrentArchive();
const setCurrentWidget = useSetCurrentWidget();
+ const extensions = useExtensions();
const [busy, setBusy] = React.useState(false);
@@ -165,9 +168,9 @@ export default function ImportExportModal({
const handleExecute = async (values) => {
if (busy) return;
-
+
setBusy(true);
- const script = await createImpExpScript(values);
+ const script = await createImpExpScript(extensions, values);
setExecuteNumber((num) => num + 1);
@@ -194,7 +197,7 @@ export default function ImportExportModal({
onSubmit={handleExecute}
initialValues={{
sourceStorageType: 'database',
- targetStorageType: importToArchive ? 'archive' : defaultFileFormat.storageType,
+ targetStorageType: importToArchive ? 'archive' : getDefaultFileFormat(extensions).storageType,
sourceArchiveFolder: archive,
targetArchiveFolder,
...initialValues,
diff --git a/packages/web/src/plugins/PluginsProvider.js b/packages/web/src/plugins/PluginsProvider.js
index 7ae3fa25d..6e9f5767d 100644
--- a/packages/web/src/plugins/PluginsProvider.js
+++ b/packages/web/src/plugins/PluginsProvider.js
@@ -9,12 +9,7 @@ export default function PluginsProvider({ children }) {
const installedPlugins = useInstalledPlugins();
const [plugins, setPlugins] = React.useState({});
const handleLoadPlugins = async () => {
- setPlugins((x) =>
- _.pick(
- x,
- installedPlugins.map((y) => y.name)
- )
- );
+ const newPlugins = {};
for (const installed of installedPlugins) {
if (!_.keys(plugins).includes(installed.name)) {
console.log('Loading module', installed.name);
@@ -26,12 +21,16 @@ export default function PluginsProvider({ children }) {
},
});
const module = eval(resp.data);
- setPlugins((v) => ({
- ...v,
- [installed.name]: module,
- }));
+ console.log('Loaded plugin', module);
+ newPlugins[installed.name] = module.__esModule ? module.default : module;
}
}
+ setPlugins((x) =>
+ _.pick(
+ { ...x, ...newPlugins },
+ installedPlugins.map((y) => y.name)
+ )
+ );
};
React.useEffect(() => {
handleLoadPlugins();
@@ -42,11 +41,16 @@ export default function PluginsProvider({ children }) {
export function usePlugins() {
const installed = useInstalledPlugins();
const loaded = React.useContext(PluginsContext);
- return installed
- .map((manifest) => ({
- packageName: manifest.name,
- manifest,
- content: loaded[manifest.name],
- }))
- .filter((x) => x.content);
+
+ return React.useMemo(
+ () =>
+ installed
+ .map((manifest) => ({
+ packageName: manifest.name,
+ manifest,
+ content: loaded[manifest.name],
+ }))
+ .filter((x) => x.content),
+ [installed, loaded]
+ );
}
diff --git a/packages/web/src/utility/UploadsProvider.js b/packages/web/src/utility/UploadsProvider.js
index 81a5de7d2..f75ab1b8f 100644
--- a/packages/web/src/utility/UploadsProvider.js
+++ b/packages/web/src/utility/UploadsProvider.js
@@ -1,9 +1,10 @@
import React from 'react';
import { useDropzone } from 'react-dropzone';
-import { findFileFormat } from '../fileformats';
import ImportExportModal from '../modals/ImportExportModal';
import useShowModal from '../modals/showModal';
+import { findFileFormat } from './fileformats';
import resolveApi from './resolveApi';
+import useExtensions from './useExtensions';
const UploadsContext = React.createContext(null);
@@ -19,6 +20,7 @@ export function useUploadsProvider() {
export function useUploadsZone() {
const { uploadListener } = useUploadsProvider();
const showModal = useShowModal();
+ const extensions = useExtensions();
const onDrop = React.useCallback(
(files) => {
@@ -43,7 +45,7 @@ export function useUploadsZone() {
if (uploadListener) {
uploadListener(fileData);
} else {
- if (findFileFormat(fileData.storageType)) {
+ if (findFileFormat(extensions, fileData.storageType)) {
showModal((modalState) => (
{
+ const resp = await axios.get(`files/analyse-excel?filePath=${encodeURIComponent(file.full)}`);
+ const sheetNames = resp.data;
+ for (const sheetName of sheetNames) {
+ newSources.push(sheetName);
+ newValues[`sourceFile_${sheetName}`] = {
+ fileName: file.full,
+ sheetName,
+ };
+ }
+ },
+
+ args: [
+ {
+ type: 'checkbox',
+ name: 'singleFile',
+ label: 'Create single file',
+ direction: 'target',
+ },
+ ],
+
+ getDefaultOutputName: (sourceName, values) => {
+ if (values.target_excel_singleFile) {
+ return sourceName;
+ }
+ return null;
+ },
+
+ getOutputParams: (sourceName, values) => {
+ if (values.target_excel_singleFile) {
+ return {
+ sheetName: values[`targetName_${sourceName}`] || sourceName,
+ fileName: 'data.xlsx',
+ };
+ }
+ return null;
+ },
+};
+
+const jsonlFormat = {
+ storageType: 'jsonl',
+ extension: 'jsonl',
+ name: 'JSON lines',
+ readerFunc: 'jsonLinesReader',
+ writerFunc: 'jsonLinesWriter',
+};
+
+export function buildFileFormats(plugins) {
+ const res = [excelFormat, jsonlFormat];
+ for (const { content } of plugins) {
+ const { fileFormats } = content;
+ if (fileFormats) res.push(...fileFormats);
+ }
+ return res;
+}
+
+export function findFileFormat(extensions, storageType) {
+ return extensions.fileFormats.find((x) => x.storageType == storageType);
+}
+
+export function getFileFormatDirections(format) {
+ if (!format) return [];
+ const res = [];
+ if (format.readerFunc) res.push('source');
+ if (format.writerFunc) res.push('target');
+ return res;
+}
+
+export function getDefaultFileFormat(extensions) {
+ return extensions.fileFormats.find((x) => x.storageType == 'csv') || jsonlFormat;
}
diff --git a/packages/web/src/utility/globalState.js b/packages/web/src/utility/globalState.js
index 9a5f576f8..51ede5906 100644
--- a/packages/web/src/utility/globalState.js
+++ b/packages/web/src/utility/globalState.js
@@ -5,6 +5,7 @@ import { useConnectionInfo, useConfig } from './metadataLoaders';
import usePrevious from './usePrevious';
import useNewQuery from '../query/useNewQuery';
import useShowModal from '../modals/showModal';
+import useExtensions from './useExtensions';
function createGlobalState(defaultValue) {
const Context = React.createContext(null);
@@ -90,6 +91,7 @@ export function useAppObjectParams() {
const currentArchive = useCurrentArchive();
const showModal = useShowModal();
const config = useConfig();
+ const extensions = useExtensions();
return {
setOpenedTabs,
diff --git a/packages/web/src/utility/metadataLoaders.js b/packages/web/src/utility/metadataLoaders.js
index 5ac8b597e..ffe8fc6c9 100644
--- a/packages/web/src/utility/metadataLoaders.js
+++ b/packages/web/src/utility/metadataLoaders.js
@@ -88,7 +88,7 @@ const connectionListLoader = () => ({
reloadTrigger: `connection-list-changed`,
});
-const insttalledPluginsLoader = () => ({
+const installedPluginsLoader = () => ({
url: 'plugins/installed',
params: {},
reloadTrigger: `installed-plugins-changed`,
@@ -251,8 +251,8 @@ export function useArchiveFolders(args) {
}
export function getInstalledPlugins(args) {
- return getCore(insttalledPluginsLoader, args) || [];
+ return getCore(installedPluginsLoader, args) || [];
}
export function useInstalledPlugins(args) {
- return useCore(insttalledPluginsLoader, args) || [];
+ return useCore(installedPluginsLoader, args) || [];
}
diff --git a/packages/web/src/utility/useExtensions.js b/packages/web/src/utility/useExtensions.js
new file mode 100644
index 000000000..6b53996c7
--- /dev/null
+++ b/packages/web/src/utility/useExtensions.js
@@ -0,0 +1,15 @@
+import React from 'react';
+import { usePlugins } from '../plugins/PluginsProvider';
+import { buildFileFormats } from './fileformats';
+
+export default function useExtensions() {
+ const plugins = usePlugins();
+ const extensions = React.useMemo(
+ () => ({
+ plugins,
+ fileFormats: buildFileFormats(plugins),
+ }),
+ [plugins]
+ );
+ return extensions;
+}
diff --git a/packages/web/src/widgets/Toolbar.js b/packages/web/src/widgets/Toolbar.js
index d0c91089d..0c3aade65 100644
--- a/packages/web/src/widgets/Toolbar.js
+++ b/packages/web/src/widgets/Toolbar.js
@@ -10,7 +10,8 @@ import { openNewTab } from '../utility/common';
import useNewFreeTable from '../freetable/useNewFreeTable';
import ImportExportModal from '../modals/ImportExportModal';
import useShowModal from '../modals/showModal';
-import { defaultFileFormat } from '../fileformats';
+import useExtensions from '../utility/useExtensions';
+import { getDefaultFileFormat } from '../utility/fileformats';
const ToolbarContainer = styled.div`
display: flex;
@@ -28,6 +29,7 @@ export default function ToolBar({ toolbarPortalRef }) {
const showModal = useShowModal();
const currentTheme = useCurrentTheme();
const setCurrentTheme = useSetCurrentTheme();
+ const extensions = useExtensions();
React.useEffect(() => {
window['dbgate_createNewConnection'] = modalState.open;
@@ -41,7 +43,7 @@ export default function ToolBar({ toolbarPortalRef }) {
modalState={modalState}
importToArchive
initialValues={{
- sourceStorageType: defaultFileFormat.storageType,
+ sourceStorageType: getDefaultFileFormat(extensions).storageType,
// sourceConnectionId: data.conid,
// sourceDatabaseName: data.database,
// sourceSchemaName: data.schemaName,