Merge branch 'master' into redis

This commit is contained in:
Jan Prochazka
2022-03-13 17:33:35 +01:00
35 changed files with 394 additions and 52 deletions

View File

@@ -174,6 +174,7 @@
initialValues.sourceDatabaseName = database;
initialValues.sourceSql = getExportQuery();
initialValues.sourceList = [pureName];
initialValues[`columns_${pureName}`] = display.getExportColumnMap();
showModal(ImportExportModal, { initialValues });
}
@@ -208,7 +209,8 @@
sql: getExportQuery(),
},
},
fmt
fmt,
display.getExportColumnMap()
);
};

View File

@@ -175,10 +175,12 @@
if (domFocusField) domFocusField.focus();
}}
on:setvisibility={e => {
for (const name of selectedColumns) {
const column = items.find(x => x.uniqueName == name);
if (column) {
display.setColumnVisibility(column.uniquePath, e.detail);
if (selectedColumns.includes(column.uniqueName)) {
for (const name of selectedColumns) {
const column = items.find(x => x.uniqueName == name);
if (column) {
display.setColumnVisibility(column.uniquePath, e.detail);
}
}
}
}}

View File

@@ -800,6 +800,7 @@
// $: console.log('containerHeight', containerHeight);
// $: console.log('COLUMNS', columns);
// $: console.log('columnSizes.realCount', columnSizes.realCount);
// $: console.log('realColumnUniqueNames', realColumnUniqueNames);
// $: console.log('columnSizes.realCount', columnSizes.realCount);

View File

@@ -55,6 +55,7 @@
import RowsArrayGrider from './RowsArrayGrider';
export let jslid;
export let display;
export const activator = createActivator('JslDataGridCore', false);
@@ -93,10 +94,12 @@
initialValues.sourceStorageType = 'archive';
initialValues.sourceArchiveFolder = archiveMatch[1];
initialValues.sourceList = [archiveMatch[2]];
initialValues[`columns_${archiveMatch[2]}`] = display.getExportColumnMap();
} else {
initialValues.sourceStorageType = 'jsldata';
initialValues.sourceJslId = jslid;
initialValues.sourceList = ['query-data'];
initialValues[`columns_query-data`] = display.getExportColumnMap();
}
showModal(ImportExportModal, { initialValues });
}
@@ -113,7 +116,8 @@
fileName: archiveMatch[2],
},
},
fmt
fmt,
display.getExportColumnMap()
);
} else {
exportQuickExportFile(
@@ -124,7 +128,8 @@
jslid,
},
},
fmt
fmt,
display.getExportColumnMap()
);
}
};

View File

@@ -99,9 +99,12 @@ export class SeriesSizes {
}
this.modelIndexes = _.range(0, this.count);
// console.log('SeriesSize:build:this.modelIndexes-before', this.modelIndexes);
// console.log('SeriesSize:build:this.hiddenAndFrozenModelIndexes', this.hiddenAndFrozenModelIndexes);
if (this.hiddenAndFrozenModelIndexes) {
this.modelIndexes = this.modelIndexes.filter(col => !this.hiddenAndFrozenModelIndexes.includes(col));
}
// console.log('SeriesSize:build:this.modelIndexes-result', this.modelIndexes);
}
public getScrollIndexOnPosition(position: number): number {

View File

@@ -135,6 +135,7 @@
initialValues.sourceDatabaseName = database;
initialValues.sourceSql = display.getExportQuery();
initialValues.sourceList = display.baseTableOrSimilar ? [display.baseTableOrSimilar.pureName] : [];
initialValues[`columns_${pureName}`] = display.getExportColumnMap();
showModal(ImportExportModal, { initialValues });
}
@@ -193,7 +194,8 @@
sql: display.getExportQuery(),
},
},
fmt
fmt,
display.getExportColumnMap()
);
};
registerQuickExportHandler(quickExportHandler);

View File

@@ -17,6 +17,7 @@ export function countColumnSizes(grider: Grider, columns, containerWidth, displa
//return this.context.measureText(txt).width;
// console.log('countColumnSizes', loadedRows.length, containerWidth);
// console.log('countColumnSizes:columns', columns);
columnSizes.maxSize = (containerWidth * 2) / 3;
columnSizes.count = columns.length;
@@ -114,10 +115,12 @@ export function countVisibleRealColumns(columnSizes, firstVisibleColumnScrollInd
) {
visibleRealColumnIndexes.push(colIndex + columnSizes.frozenCount);
}
// console.log('countVisibleRealColumns:visibleRealColumnIndexes', visibleRealColumnIndexes);
// real columns
for (let colIndex of visibleRealColumnIndexes) {
let modelColumnIndex = columnSizes.realToModel(colIndex);
// console.log('countVisibleRealColumns:modelColumnIndex', modelColumnIndex);
modelIndexes[colIndex] = modelColumnIndex;
let col = columns[modelColumnIndex];
@@ -129,6 +132,7 @@ export function countVisibleRealColumns(columnSizes, firstVisibleColumnScrollInd
width,
});
}
// console.log('countVisibleRealColumns:realColumns', realColumns);
return realColumns;
}

View File

@@ -24,6 +24,7 @@
export let selectedIndex = 0;
export let clickable = false;
export let disableFocusOutline = false;
export let emptyMessage = null;
export let domTable = undefined;
@@ -99,6 +100,11 @@
{/each}
</tr>
{/each}
{#if emptyMessage && rows.length == 0}
<tr>
<td colspan={columnList.length}>{emptyMessage}</td>
</tr>
{/if}
</tbody>
</table>

View File

@@ -16,6 +16,7 @@
import { createGridCache, FreeTableGridDisplay } from 'dbgate-datalib';
import { writable } from 'svelte/store';
import uuidv1 from 'uuid/v1';
import { registerQuickExportHandler } from '../buttons/ToolStripExportButton.svelte';
import registerCommand from '../commands/registerCommand';
import DataGridCore from '../datagrid/DataGridCore.svelte';
@@ -24,6 +25,8 @@
import { apiCall } from '../utility/api';
import { registerMenu } from '../utility/contextMenu';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import createQuickExportMenu from '../utility/createQuickExportMenu';
import { exportQuickExportFile } from '../utility/exportFileTools';
import FreeTableGrider from './FreeTableGrider';
import MacroPreviewGrider from './MacroPreviewGrider';
@@ -51,10 +54,31 @@
initialValues.sourceStorageType = 'jsldata';
initialValues.sourceJslId = jslid;
initialValues.sourceList = ['editor-data'];
initialValues[`columns_editor-data`] = display.getExportColumnMap();
showModal(ImportExportModal, { initialValues: initialValues });
}
registerMenu({ command: 'freeTableGrid.export', tag: 'export' });
const quickExportHandler = fmt => async () => {
const jslid = uuidv1();
await apiCall('jsldata/save-free-table', { jslid, data: modelState.value });
exportQuickExportFile(
'editor-data',
{
functionName: 'jslDataReader',
props: {
jslid,
},
},
fmt,
display.getExportColumnMap()
);
};
registerQuickExportHandler(quickExportHandler);
registerMenu(() => ({
...createQuickExportMenu(quickExportHandler, { command: 'freeTableGrid.export' }),
tag: 'export',
}));
</script>
<DataGridCore {...$$props} {grider} {display} frameSelection={!!macroPreview} bind:selectedCellsPublished />

View File

@@ -42,11 +42,14 @@
<script lang="ts">
import { onMount } from 'svelte';
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 getAsArray from '../utility/getAsArray';
@@ -189,6 +192,11 @@
header: 'Preview',
slot: 0,
},
{
fieldName: 'columns',
header: 'Columns',
slot: 2,
},
]}
>
<svelte:fragment slot="0" let:row>
@@ -214,6 +222,18 @@
)}
/>
</svelte:fragment>
<svelte:fragment slot="2" let:row>
{@const columnCount = ($values[`columns_${row}`] || []).filter(x => !x.skip).length}
<Link
onClick={() => {
showModal(ColumnMapModal, {
value: $values[`columns_${row}`],
onConfirm: value => setFieldValue(`columns_${row}`, value),
});
}}
>{columnCount > 0 ? `(${columnCount} columns)` : '(copy from source)'}
</Link>
</svelte:fragment>
</TableControl>
</div>
</div>

View File

@@ -25,12 +25,20 @@ export default class ScriptWriter {
this.packageNames.push(...extractShellApiPlugins(functionName, props));
}
assignValue(variableName, jsonValue) {
this.put(`const ${variableName} = ${JSON.stringify(jsonValue)};`);
}
requirePackage(packageName) {
this.packageNames.push(packageName);
}
copyStream(sourceVar, targetVar) {
this.put(`await dbgateApi.copyStream(${sourceVar}, ${targetVar});`);
copyStream(sourceVar, targetVar, colmapVar = null) {
if (colmapVar) {
this.put(`await dbgateApi.copyStream(${sourceVar}, ${targetVar}, {columns: ${colmapVar}});`);
} else {
this.put(`await dbgateApi.copyStream(${sourceVar}, ${targetVar});`);
}
}
comment(s) {

View File

@@ -160,6 +160,21 @@ function getTargetExpr(extensions, sourceName, values, targetConnection, targetD
throw new Error(`Unknown target storage type: ${targetStorageType}`);
}
export function normalizeExportColumnMap(colmap) {
if (!colmap) {
return null;
}
if (!colmap.find(x => !x.ignore)) {
// all values are ignored, ignore column map
return null;
}
colmap = colmap.filter(x => !x.skip);
if (colmap.length > 0) {
return colmap.map(x => _.omit(x, ['ignore']));
}
return null;
}
export default async function createImpExpScript(extensions, values, addEditorInfo = true) {
const script = new ScriptWriter(values.startVariableIndex || 0);
@@ -186,7 +201,15 @@ export default async function createImpExpScript(extensions, values, addEditorIn
// @ts-ignore
script.assign(targetVar, ...getTargetExpr(extensions, sourceName, values, targetConnection, targetDriver));
script.copyStream(sourceVar, targetVar);
const colmap = normalizeExportColumnMap(values[`columns_${sourceName}`] );
let colmapVar = null;
if (colmap) {
colmapVar = script.allocVariable();
script.assignValue(colmapVar, colmap);
}
script.copyStream(sourceVar, targetVar, colmapVar);
script.put();
}
if (addEditorInfo) {

View File

@@ -0,0 +1,91 @@
<script lang="ts">
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import Link from '../elements/Link.svelte';
import TableControl from '../elements/TableControl.svelte';
import CheckboxField from '../forms/CheckboxField.svelte';
import FormProvider from '../forms/FormProvider.svelte';
import FormSubmit from '../forms/FormSubmit.svelte';
import TextField from '../forms/TextField.svelte';
import ModalBase from './ModalBase.svelte';
import { closeCurrentModal } from './modalTools';
export let header = 'Configure columns';
export let onConfirm;
export let value = [];
</script>
<FormProvider>
<ModalBase {...$$restProps}>
<div slot="header">{header}</div>
<div class="m-3">
When no columns are defined in this mapping, source row is copied to target without any modifications
</div>
<TableControl
columns={[
{ fieldName: 'use', header: 'Use', slot: 4 },
{ fieldName: 'src', header: 'Source column', slot: 1 },
{ fieldName: 'dst', header: 'Target column', slot: 2 },
{ fieldName: 'actions', header: '', slot: 3 },
]}
rows={value || []}
emptyMessage="No transform defined"
>
<svelte:fragment slot="4" let:row let:index>
<CheckboxField
checked={!row['skip']}
on:change={e =>
(value = (value || []).map((x, i) => (i == index ? { ...x, skip: !e.target.checked, ignore: false } : x)))}
/>
</svelte:fragment>
<svelte:fragment slot="1" let:row let:index>
<TextField
value={row['src']}
on:change={e =>
(value = (value || []).map((x, i) => (i == index ? { ...x, src: e.target.value, ignore: false } : x)))}
/>
</svelte:fragment>
<svelte:fragment slot="2" let:row let:index>
<TextField
value={row['dst']}
on:change={e =>
(value = (value || []).map((x, i) => (i == index ? { ...x, dst: e.target.value, ignore: false } : x)))}
/>
</svelte:fragment>
<svelte:fragment slot="3" let:index>
<Link
onClick={() => {
value = value.filter((x, i) => i != index);
}}>Remove</Link
>
</svelte:fragment>
</TableControl>
<svelte:fragment slot="footer">
<FormSubmit
value="OK"
on:click={() => {
closeCurrentModal();
onConfirm(!value || value.length == 0 ? null : value);
}}
/>
<FormStyledButton type="button" value="Close" on:click={closeCurrentModal} />
<FormStyledButton
type="button"
value="Add column"
on:click={() => {
value = [...(value || []), {}];
}}
/>
<FormStyledButton
type="button"
value="Reset"
on:click={() => {
value = [];
}}
/>
</svelte:fragment>
</ModalBase>
</FormProvider>

View File

@@ -34,7 +34,7 @@
import { writable } from 'svelte/store';
import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte';
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
import ToolStripExportButton from '../buttons/ToolStripExportButton.svelte';
import ToolStripExportButton, { createQuickExportHandlerRef } from '../buttons/ToolStripExportButton.svelte';
import registerCommand from '../commands/registerCommand';
import DataGrid from '../datagrid/DataGrid.svelte';
import ErrorInfo from '../elements/ErrorInfo.svelte';
@@ -137,6 +137,8 @@ import ToolStripExportButton from '../buttons/ToolStripExportButton.svelte';
// display is overridden in FreeTableGridCore, this is because of column manager
$: display = new FreeTableGridDisplay($modelState.value, $config, config.update, null, null);
const quickExportHandlerRef = createQuickExportHandlerRef();
</script>
{#if isLoading}
@@ -161,7 +163,7 @@ import ToolStripExportButton from '../buttons/ToolStripExportButton.svelte';
/>
<svelte:fragment slot="toolstrip">
<ToolStripCommandButton command="freeTable.save" />
<ToolStripExportButton command="freeTableGrid.export" />
<ToolStripExportButton command="freeTableGrid.export" {quickExportHandlerRef} />
</svelte:fragment>
</ToolStripContainer>
{/if}

View File

@@ -22,6 +22,8 @@
import useEditorData from '../query/useEditorData';
import invalidateCommands from '../commands/invalidateCommands';
import createActivator, { getActiveComponent } from '../utility/createActivator';
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
import ToolStripSaveButton from '../buttons/ToolStripSaveButton.svelte';
export let tabid;
@@ -70,14 +72,20 @@
}
</script>
<AceEditor
value={$editorState.value || ''}
menu={createMenu()}
on:input={e => setEditorData(e.detail)}
on:focus={() => {
activator.activate();
invalidateCommands();
}}
bind:this={domEditor}
mode="json"
/>
<ToolStripContainer>
<AceEditor
value={$editorState.value || ''}
menu={createMenu()}
on:input={e => setEditorData(e.detail)}
on:focus={() => {
activator.activate();
invalidateCommands();
}}
bind:this={domEditor}
mode="json"
/>
<svelte:fragment slot="toolstrip">
<ToolStripSaveButton idPrefix="json" />
</svelte:fragment>
</ToolStripContainer>

View File

@@ -3,8 +3,9 @@ import getElectron from './getElectron';
import { showSnackbar, showSnackbarInfo, showSnackbarError, closeSnackbar } from '../utility/snackbar';
import resolveApi from './resolveApi';
import { apiCall, apiOff, apiOn } from './api';
import { normalizeExportColumnMap } from '../impexp/createImpExpScript';
export async function exportQuickExportFile(dataName, reader, format) {
export async function exportQuickExportFile(dataName, reader, format, columnMap = null) {
const electron = getElectron();
let filePath;
@@ -31,7 +32,14 @@ export async function exportQuickExportFile(dataName, reader, format) {
const writer = format.createWriter(filePath, dataName);
script.assign(targetVar, writer.functionName, writer.props);
script.copyStream(sourceVar, targetVar);
const colmap = normalizeExportColumnMap(columnMap);
let colmapVar = null;
if (colmap) {
colmapVar = script.allocVariable();
script.assignValue(colmapVar, colmap);
}
script.copyStream(sourceVar, targetVar, colmapVar);
script.put();
const resp = await apiCall('runners/start', { script: script.getScript() });

View File

@@ -37,6 +37,7 @@
import { useAppFiles, useArchiveFolders } from '../utility/metadataLoaders';
import openNewTab from '../utility/openNewTab';
import WidgetsInnerContainer from './WidgetsInnerContainer.svelte';
import { showSnackbarError } from '../utility/snackbar';
let filter = '';
@@ -66,12 +67,27 @@
});
}
async function handleNewConfigFile(fileName, content) {
if (!(await apiCall('apps/create-config-file', { fileName, content, appFolder: $currentApplication }))) {
showSnackbarError('File not created, probably already exists');
}
}
function createAddMenu() {
return [
{
text: 'New SQL command',
onClick: () => handleNewSqlFile('command.sql', 'Create new SQL command', COMMAND_TEMPLATE),
},
{
text: 'New virtual references file',
onClick: () => handleNewConfigFile('virtual-references.config.json', []),
},
{
text: 'New disctionary descriptions file',
onClick: () => handleNewConfigFile('dictionary-descriptions.config.json', []),
},
// { text: 'New query view', onClick: () => handleNewSqlFile('query.sql', 'Create new SQL query', QUERY_TEMPLATE) },
];
}

View File

@@ -387,15 +387,17 @@
draggingDbGroupTarget = null;
}}
>
<FontIcon icon={getDbIcon(tabGroup.tabDbKey)} padRight />
{tabGroup.tabDbName}
<div class="db-name-inner">
<FontIcon icon={getDbIcon(tabGroup.tabDbKey)} />
{tabGroup.tabDbName}
</div>
<span
<div
class="close-button-right tabCloseButton"
on:click={e => closeMultipleTabs(tab => tabGroup.tabs.find(x => x.tabid == tab.tabid))}
>
<FontIcon icon="icon close" />
</span>
</div>
</div>
<div class="db-group">
{#each tabGroup.tabs as tab}
@@ -505,7 +507,10 @@
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.db-name-inner {
justify-content: center;
flex-grow: 1;
}
/* .db-name:hover {
background-color: var(--theme-bg-3);
@@ -541,7 +546,6 @@
margin-left: 5px;
margin-right: 5px;
color: var(--theme-font-3);
float: right;
}
.close-button:hover {