mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 03:16:01 +00:00
373 lines
13 KiB
Svelte
373 lines
13 KiB
Svelte
<script lang="ts" context="module">
|
|
async function addFileToSourceListDefault({ fileName, shortName, isDownload }, newSources, newValues) {
|
|
const sourceName = shortName;
|
|
newSources.push(sourceName);
|
|
newValues[`sourceFile_${sourceName}`] = {
|
|
fileName,
|
|
isDownload,
|
|
};
|
|
}
|
|
|
|
export async function addFilesToSourceList(
|
|
extensions,
|
|
files,
|
|
values,
|
|
valuesStore,
|
|
preferedStorageType = undefined,
|
|
setPreviewSource = undefined
|
|
) {
|
|
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, apiCall);
|
|
}
|
|
}
|
|
const templateTarget = values['targetName___TEMPLATE__'];
|
|
newValues['sourceList'] = [
|
|
...(values.sourceList || []).filter(x => !newSources.includes(x) && x != '__TEMPLATE__'),
|
|
...newSources,
|
|
];
|
|
if (preferedStorageType && preferedStorageType != values.sourceStorageType) {
|
|
newValues['sourceStorageType'] = preferedStorageType;
|
|
}
|
|
if (templateTarget) {
|
|
const source = newSources[0];
|
|
if (source) {
|
|
newValues[`targetName_${source}`] = templateTarget;
|
|
}
|
|
}
|
|
const newValuesAll = {
|
|
...values,
|
|
...newValues,
|
|
};
|
|
delete newValuesAll['targetName___TEMPLATE__'];
|
|
valuesStore.set(newValuesAll);
|
|
if (setPreviewSource && newSources.length == 1) {
|
|
setPreviewSource(newSources[0]);
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script lang="ts">
|
|
import { writable } from 'svelte/store';
|
|
import Link from '../elements/Link.svelte';
|
|
import TableControl from '../elements/TableControl.svelte';
|
|
import CheckboxField from '../forms/CheckboxField.svelte';
|
|
import { getFormContext } from '../forms/FormProviderCore.svelte';
|
|
import TextField from '../forms/TextField.svelte';
|
|
import FontIcon from '../icons/FontIcon.svelte';
|
|
import ColumnMapModal from '../modals/ColumnMapModal.svelte';
|
|
import { showModal } from '../modals/modalTools';
|
|
import { findFileFormat } from '../plugins/fileformats';
|
|
import { extensions } from '../stores';
|
|
import { apiCall } from '../utility/api';
|
|
import getAsArray from '../utility/getAsArray';
|
|
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
|
|
import { setUploadListener } from '../utility/uploadFiles';
|
|
import { createPreviewReader, getTargetName } from './createImpExpScript';
|
|
import SourceAction from './SourceAction.svelte';
|
|
import SourceName from './SourceName.svelte';
|
|
|
|
import SourceTargetConfig from './SourceTargetConfig.svelte';
|
|
import useEffect from '../utility/useEffect';
|
|
import { compositeDbNameIfNeeded } from 'dbgate-tools';
|
|
import createRef from '../utility/createRef';
|
|
import DropDownButton from '../buttons/DropDownButton.svelte';
|
|
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
|
import { _t } from '../translations';
|
|
|
|
// export let uploadedFile = undefined;
|
|
// export let openedFile = undefined;
|
|
export let previewReaderStore;
|
|
export let isTabActive;
|
|
export let isRunning = false;
|
|
|
|
const { values, setFieldValue } = getFormContext();
|
|
|
|
// $: console.log('VALUES', $values);
|
|
// $: console.log('$sourceDbinfo', $sourceDbinfo);
|
|
// $: console.log('$targetDbinfo', $targetDbinfo);
|
|
|
|
$: sourceConnectionInfo = useConnectionInfo({ conid: $values.sourceConnectionId });
|
|
$: targetConnectionInfo = useConnectionInfo({ conid: $values.targetConnectionId });
|
|
|
|
$: sourceDbinfo = useDatabaseInfo({
|
|
conid: $values.sourceConnectionId,
|
|
database: compositeDbNameIfNeeded($sourceConnectionInfo, $values.sourceDatabaseName, $values.sourceSchemaName),
|
|
});
|
|
$: targetDbinfo = useDatabaseInfo({
|
|
conid: $values.targetConnectionId,
|
|
database: compositeDbNameIfNeeded($targetConnectionInfo, $values.targetDatabaseName, $values.targetSchemaName),
|
|
});
|
|
|
|
$: sourceEngine = $sourceConnectionInfo?.engine;
|
|
$: sourceList = $values.sourceList;
|
|
|
|
let targetEditKey = 0;
|
|
export let progressHolder = null;
|
|
|
|
const previewSource = writable(null);
|
|
|
|
$: supportsPreview =
|
|
!!findFileFormat($extensions, $values.sourceStorageType) || $values.sourceStorageType == 'archive';
|
|
|
|
$: {
|
|
$values;
|
|
handleChangePreviewSource($previewSource);
|
|
}
|
|
|
|
const handleChangePreviewSource = async source => {
|
|
if (source && supportsPreview) {
|
|
const reader = await createPreviewReader($extensions, $values, source);
|
|
if (previewReaderStore) previewReaderStore.set(reader);
|
|
} else {
|
|
if (previewReaderStore) previewReaderStore.set(null);
|
|
}
|
|
};
|
|
|
|
export function addUploadedFile(file) {
|
|
addFilesToSourceList(
|
|
$extensions,
|
|
[
|
|
{
|
|
fileName: file.filePath,
|
|
shortName: file.shortName,
|
|
},
|
|
],
|
|
$values,
|
|
values,
|
|
!sourceList || sourceList.length == 0 ? file.storageType : null,
|
|
previewSource.set
|
|
);
|
|
// setFieldValue('sourceList', [...(sourceList || []), file.originalName]);
|
|
targetEditKey += 1;
|
|
}
|
|
|
|
$: effectActiveTab = useEffect(() => {
|
|
if (isTabActive) {
|
|
setUploadListener(addUploadedFile);
|
|
return () => {
|
|
setUploadListener(null);
|
|
};
|
|
} else {
|
|
return () => {};
|
|
}
|
|
});
|
|
|
|
// const lastSourcesRef = createRef(null);
|
|
// function setFixedTargetForNewSources(values, valuesStore) {
|
|
// if (lastSourcesRef.get() && values.fixedTargetPureName) {
|
|
// const newSources = values.sourceList.filter(x => !lastSourcesRef.get()?.includes(x));
|
|
// const newValues = {};
|
|
// for (const source of newSources) {
|
|
// if (values.fixedTargetPureName) {
|
|
// if (!values[`targetName_${source}`]) {
|
|
// newValues[`targetName_${source}`] = values.fixedTargetPureName;
|
|
// }
|
|
// if (!values[`actionType_${source}`]) {
|
|
// newValues[`actionType_${source}`] = 'appendData';
|
|
// }
|
|
// }
|
|
// }
|
|
// valuesStore.set({
|
|
// ...values,
|
|
// ...newValues,
|
|
// });
|
|
// }
|
|
// lastSourcesRef.set(values.sourceList);
|
|
// }
|
|
|
|
// $: setFixedTargetForNewSources($values, values);
|
|
|
|
$effectActiveTab;
|
|
</script>
|
|
|
|
<div class="flex1">
|
|
<div class="flex">
|
|
<SourceTargetConfig
|
|
direction="source"
|
|
storageTypeField="sourceStorageType"
|
|
connectionIdField="sourceConnectionId"
|
|
databaseNameField="sourceDatabaseName"
|
|
archiveFolderField="sourceArchiveFolder"
|
|
schemaNameField="sourceSchemaName"
|
|
tablesField="sourceList"
|
|
engine={sourceEngine}
|
|
setPreviewSource={previewSource.set}
|
|
/>
|
|
<div class="arrow">
|
|
<FontIcon icon="icon arrow-right-bold" />
|
|
</div>
|
|
<SourceTargetConfig
|
|
direction="target"
|
|
storageTypeField="targetStorageType"
|
|
connectionIdField="targetConnectionId"
|
|
databaseNameField="targetDatabaseName"
|
|
archiveFolderField="targetArchiveFolder"
|
|
schemaNameField="targetSchemaName"
|
|
/>
|
|
</div>
|
|
|
|
<div class="m-2">
|
|
<div class="title"><FontIcon icon="icon tables" /> {_t('importExport.mapSourceTablesFiles', { defaultMessage: "Map source tables/files" })}</div>
|
|
|
|
{#key targetEditKey}
|
|
{#key progressHolder}
|
|
<TableControl
|
|
rows={$values.sourceList || []}
|
|
columns={[
|
|
{
|
|
fieldName: 'source',
|
|
header: _t('importExport.source', { defaultMessage: "Source" }),
|
|
component: SourceName,
|
|
getProps: row => ({ name: row }),
|
|
},
|
|
{
|
|
fieldName: 'action',
|
|
header: _t('importExport.action', { defaultMessage: "Action" }),
|
|
component: SourceAction,
|
|
getProps: row => ({ name: row, targetDbinfo }),
|
|
},
|
|
{
|
|
fieldName: 'target',
|
|
header: _t('importExport.target', { defaultMessage: "Target" }),
|
|
slot: 1,
|
|
},
|
|
supportsPreview && {
|
|
fieldName: 'preview',
|
|
header: _t('importExport.preview', { defaultMessage: "Preview" }),
|
|
slot: 0,
|
|
},
|
|
!!progressHolder && {
|
|
fieldName: 'status',
|
|
header: _t('importExport.status', { defaultMessage: "Status" }),
|
|
slot: 3,
|
|
},
|
|
{
|
|
fieldName: 'columns',
|
|
header: _t('importExport.columns', { defaultMessage: "Columns" }),
|
|
slot: 2,
|
|
},
|
|
]}
|
|
>
|
|
<svelte:fragment slot="0" let:row>
|
|
{#if supportsPreview}
|
|
<CheckboxField
|
|
checked={$previewSource == row}
|
|
on:change={e => {
|
|
// @ts-ignore
|
|
if (e.target.checked) $previewSource = row;
|
|
else $previewSource = null;
|
|
}}
|
|
/>
|
|
{/if}
|
|
</svelte:fragment>
|
|
<svelte:fragment slot="1" let:row>
|
|
<div class="flex">
|
|
<TextField
|
|
value={getTargetName($extensions, row, $values)}
|
|
on:input={e =>
|
|
setFieldValue(
|
|
`targetName_${row}`,
|
|
// @ts-ignore
|
|
e.target.value
|
|
)}
|
|
data-testid={`ImportExportConfigurator_targetName_${row}`}
|
|
/>
|
|
{#if $targetDbinfo}
|
|
<DropDownButton
|
|
menu={() => {
|
|
return $targetDbinfo.tables.map(opt => ({
|
|
text: opt.pureName,
|
|
onClick: () => {
|
|
setFieldValue(`targetName_${row}`, opt.pureName);
|
|
targetEditKey += 1;
|
|
},
|
|
}));
|
|
}}
|
|
/>
|
|
{/if}
|
|
</div>
|
|
</svelte:fragment>
|
|
<svelte:fragment slot="2" let:row>
|
|
{@const columnCount = ($values[`columns_${row}`] || []).filter(x => !x.skip).length}
|
|
<Link
|
|
onClick={() => {
|
|
const targetNameLower = ($values[`targetName_${row}`] || row)?.toLowerCase();
|
|
showModal(ColumnMapModal, {
|
|
initialValue: $values[`columns_${row}`],
|
|
sourceTableInfo: $sourceDbinfo?.tables?.find(x => x.pureName?.toLowerCase() == row?.toLowerCase()),
|
|
targetTableInfo: $targetDbinfo?.tables?.find(x => x.pureName?.toLowerCase() == targetNameLower),
|
|
onConfirm: value => {
|
|
setFieldValue(`columns_${row}`, value);
|
|
targetEditKey += 1;
|
|
},
|
|
});
|
|
}}
|
|
>{columnCount > 0 ? `(${columnCount} columns)` : '(copy from source)'}
|
|
</Link>
|
|
</svelte:fragment>
|
|
<svelte:fragment slot="3" let:row>
|
|
{#if progressHolder[row]?.status == 'running' && isRunning}
|
|
<FontIcon icon="icon loading" />
|
|
{#if progressHolder[row]?.writtenRowCount}
|
|
{progressHolder[row]?.writtenRowCount} rows writtem
|
|
{:else if progressHolder[row]?.readRowCount}
|
|
{progressHolder[row]?.readRowCount} rows read
|
|
{:else}
|
|
Running
|
|
{/if}
|
|
{:else if progressHolder[row]?.status == 'error'}
|
|
<FontIcon icon="img error" /> Error
|
|
{#if progressHolder[row]?.errorMessage}
|
|
<FontIcon
|
|
icon="img info"
|
|
title={progressHolder[row]?.errorMessage}
|
|
on:click={() => showModal(ErrorMessageModal, { message: progressHolder[row]?.errorMessage })}
|
|
style="cursor: pointer"
|
|
data-testid={`ImportExportConfigurator_errorInfoIcon_${row}`}
|
|
/>
|
|
{/if}
|
|
{:else if progressHolder[row]?.status == 'done'}
|
|
<FontIcon icon="img ok" />
|
|
{#if progressHolder[row]?.writtenRowCount}
|
|
{progressHolder[row]?.writtenRowCount} rows written
|
|
{:else if progressHolder[row]?.readRowCount}
|
|
{progressHolder[row]?.readRowCount} rows written
|
|
{:else}
|
|
Done
|
|
{/if}
|
|
{:else}
|
|
<FontIcon icon="icon wait" />
|
|
{#if progressHolder[row]?.writtenRowCount}
|
|
{progressHolder[row]?.writtenRowCount} rows writtem
|
|
{:else if progressHolder[row]?.readRowCount}
|
|
{progressHolder[row]?.readRowCount} rows read
|
|
{:else}
|
|
Queued
|
|
{/if}
|
|
{/if}
|
|
</svelte:fragment>
|
|
</TableControl>
|
|
{/key}
|
|
{/key}
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.arrow {
|
|
font-size: 30px;
|
|
color: var(--theme-icon-blue);
|
|
align-self: center;
|
|
}
|
|
|
|
.title {
|
|
font-size: 20px;
|
|
text-align: center;
|
|
margin: 10px 0px;
|
|
}
|
|
</style>
|