mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-26 17:55:59 +00:00
run macros in table data editor #68
This commit is contained in:
@@ -19,4 +19,6 @@ export interface MacroDefinition {
|
|||||||
export interface MacroSelectedCell {
|
export interface MacroSelectedCell {
|
||||||
column: string;
|
column: string;
|
||||||
row: number;
|
row: number;
|
||||||
|
rowData: any;
|
||||||
|
value: any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import uuidv1 from 'uuid/v1';
|
|||||||
import uuidv4 from 'uuid/v4';
|
import uuidv4 from 'uuid/v4';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { MacroDefinition, MacroSelectedCell } from './MacroDefinition';
|
import { MacroDefinition, MacroSelectedCell } from './MacroDefinition';
|
||||||
|
import { ChangeSet, setChangeSetValue } from './ChangeSet';
|
||||||
|
import { GridDisplay } from './GridDisplay';
|
||||||
|
|
||||||
const getMacroFunction = {
|
const getMacroFunction = {
|
||||||
transformValue: code => `
|
transformValue: code => `
|
||||||
@@ -183,3 +185,55 @@ export function runMacro(
|
|||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function compileMacroFunction(macro: MacroDefinition, errors = []) {
|
||||||
|
if (!macro) return null;
|
||||||
|
let func;
|
||||||
|
try {
|
||||||
|
func = eval(getMacroFunction[macro.type](macro.code));
|
||||||
|
return func;
|
||||||
|
} catch (err) {
|
||||||
|
errors.push(`Error compiling macro ${macro.name}: ${err.message}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runMacroOnValue(compiledFunc, macroArgs, value, rowIndex, row, column, errors = []) {
|
||||||
|
if (!compiledFunc) return value;
|
||||||
|
try {
|
||||||
|
const res = compiledFunc(value, macroArgs, modules, rowIndex, row, column);
|
||||||
|
return res;
|
||||||
|
} catch (err) {
|
||||||
|
errors.push(`Error processing column ${column} on row ${rowIndex}: ${err.message}`);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runMacroOnChangeSet(
|
||||||
|
macro: MacroDefinition,
|
||||||
|
macroArgs: {},
|
||||||
|
selectedCells: MacroSelectedCell[],
|
||||||
|
changeSet: ChangeSet,
|
||||||
|
display: GridDisplay
|
||||||
|
): ChangeSet {
|
||||||
|
const errors = [];
|
||||||
|
const compiledMacroFunc = compileMacroFunction(macro, errors);
|
||||||
|
if (!compiledMacroFunc) return null;
|
||||||
|
|
||||||
|
let res = changeSet;
|
||||||
|
for (const cell of selectedCells) {
|
||||||
|
const definition = display.getChangeSetField(cell.rowData, cell.column, undefined);
|
||||||
|
const macroResult = runMacroOnValue(
|
||||||
|
compiledMacroFunc,
|
||||||
|
macroArgs,
|
||||||
|
cell.value,
|
||||||
|
cell.row,
|
||||||
|
cell.rowData,
|
||||||
|
cell.column,
|
||||||
|
errors
|
||||||
|
);
|
||||||
|
res = setChangeSetValue(res, definition, macroResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { recentDatabases, currentDatabase, getRecentDatabases } from '../stores'
|
|||||||
import registerCommand from './registerCommand';
|
import registerCommand from './registerCommand';
|
||||||
|
|
||||||
currentDatabase.subscribe(value => {
|
currentDatabase.subscribe(value => {
|
||||||
console.log('DB', value);
|
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
recentDatabases.update(list => {
|
recentDatabases.update(list => {
|
||||||
const res = [
|
const res = [
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ import {
|
|||||||
findExistingChangeSetItem,
|
findExistingChangeSetItem,
|
||||||
getChangeSetInsertedRows,
|
getChangeSetInsertedRows,
|
||||||
GridDisplay,
|
GridDisplay,
|
||||||
|
MacroDefinition,
|
||||||
|
MacroSelectedCell,
|
||||||
revertChangeSetRowChanges,
|
revertChangeSetRowChanges,
|
||||||
setChangeSetValue,
|
setChangeSetValue,
|
||||||
|
compileMacroFunction,
|
||||||
|
runMacroOnValue,
|
||||||
} from 'dbgate-datalib';
|
} from 'dbgate-datalib';
|
||||||
import Grider, { GriderRowStatus } from './Grider';
|
import Grider, { GriderRowStatus } from './Grider';
|
||||||
|
|
||||||
@@ -21,8 +25,18 @@ export default class ChangeSetGrider extends Grider {
|
|||||||
private rowStatusCache;
|
private rowStatusCache;
|
||||||
private rowDefinitionsCache;
|
private rowDefinitionsCache;
|
||||||
private batchChangeSet: ChangeSet;
|
private batchChangeSet: ChangeSet;
|
||||||
|
private _errors = null;
|
||||||
|
private compiledMacroFunc;
|
||||||
|
|
||||||
constructor(public sourceRows: any[], public changeSetState, public dispatchChangeSet, public display: GridDisplay) {
|
constructor(
|
||||||
|
public sourceRows: any[],
|
||||||
|
public changeSetState,
|
||||||
|
public dispatchChangeSet,
|
||||||
|
public display: GridDisplay,
|
||||||
|
public macro: MacroDefinition,
|
||||||
|
public macroArgs: {},
|
||||||
|
public selectedCells: MacroSelectedCell[]
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
this.changeSet = changeSetState && changeSetState.value;
|
this.changeSet = changeSetState && changeSetState.value;
|
||||||
this.insertedRows = getChangeSetInsertedRows(this.changeSet, display.baseTable);
|
this.insertedRows = getChangeSetInsertedRows(this.changeSet, display.baseTable);
|
||||||
@@ -32,6 +46,11 @@ export default class ChangeSetGrider extends Grider {
|
|||||||
this.rowStatusCache = {};
|
this.rowStatusCache = {};
|
||||||
this.rowDefinitionsCache = {};
|
this.rowDefinitionsCache = {};
|
||||||
this.batchChangeSet = null;
|
this.batchChangeSet = null;
|
||||||
|
this.compiledMacroFunc = compileMacroFunction(macro, this._errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
get errors() {
|
||||||
|
return this._errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
getRowSource(index: number) {
|
getRowSource(index: number) {
|
||||||
@@ -49,7 +68,11 @@ export default class ChangeSetGrider extends Grider {
|
|||||||
const insertedRowIndex = this.getInsertedRowIndex(index);
|
const insertedRowIndex = this.getInsertedRowIndex(index);
|
||||||
const rowDefinition = this.display.getChangeSetRow(row, insertedRowIndex);
|
const rowDefinition = this.display.getChangeSetRow(row, insertedRowIndex);
|
||||||
const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(this.changeSet, rowDefinition);
|
const [matchedField, matchedChangeSetItem] = findExistingChangeSetItem(this.changeSet, rowDefinition);
|
||||||
const rowUpdated = matchedChangeSetItem ? { ...row, ...matchedChangeSetItem.fields } : row;
|
const rowUpdated = matchedChangeSetItem
|
||||||
|
? { ...row, ...matchedChangeSetItem.fields }
|
||||||
|
: this.compiledMacroFunc
|
||||||
|
? { ...row }
|
||||||
|
: row;
|
||||||
let status = 'regular';
|
let status = 'regular';
|
||||||
if (matchedChangeSetItem && matchedField == 'updates') status = 'updated';
|
if (matchedChangeSetItem && matchedField == 'updates') status = 'updated';
|
||||||
if (matchedField == 'deletes') status = 'deleted';
|
if (matchedField == 'deletes') status = 'deleted';
|
||||||
@@ -59,6 +82,23 @@ export default class ChangeSetGrider extends Grider {
|
|||||||
modifiedFields:
|
modifiedFields:
|
||||||
matchedChangeSetItem && matchedChangeSetItem.fields ? new Set(Object.keys(matchedChangeSetItem.fields)) : null,
|
matchedChangeSetItem && matchedChangeSetItem.fields ? new Set(Object.keys(matchedChangeSetItem.fields)) : null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.compiledMacroFunc) {
|
||||||
|
for (const cell of this.selectedCells) {
|
||||||
|
if (cell.row != index) continue;
|
||||||
|
const newValue = runMacroOnValue(
|
||||||
|
this.compiledMacroFunc,
|
||||||
|
this.macroArgs,
|
||||||
|
rowUpdated[cell.column],
|
||||||
|
index,
|
||||||
|
rowUpdated,
|
||||||
|
cell.column,
|
||||||
|
this._errors
|
||||||
|
);
|
||||||
|
rowUpdated[cell.column] = newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.rowDataCache[index] = rowUpdated;
|
this.rowDataCache[index] = rowUpdated;
|
||||||
this.rowStatusCache[index] = rowStatus;
|
this.rowStatusCache[index] = rowStatus;
|
||||||
this.rowDefinitionsCache[index] = rowDefinition;
|
this.rowDefinitionsCache[index] = rowDefinition;
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { setContext } from 'svelte';
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import { runMacroOnChangeSet } from 'dbgate-datalib';
|
||||||
|
|
||||||
import HorizontalSplitter from '../elements/HorizontalSplitter.svelte';
|
import HorizontalSplitter from '../elements/HorizontalSplitter.svelte';
|
||||||
|
import VerticalSplitter from '../elements/VerticalSplitter.svelte';
|
||||||
import FormViewFilters from '../formview/FormViewFilters.svelte';
|
import FormViewFilters from '../formview/FormViewFilters.svelte';
|
||||||
|
import { extractMacroValuesForMacro } from '../freetable/FreeTableGrid.svelte';
|
||||||
|
import MacroDetail from '../freetable/MacroDetail.svelte';
|
||||||
|
import MacroManager from '../freetable/MacroManager.svelte';
|
||||||
|
import createRef from '../utility/createRef';
|
||||||
import WidgetColumnBar from '../widgets/WidgetColumnBar.svelte';
|
import WidgetColumnBar from '../widgets/WidgetColumnBar.svelte';
|
||||||
import WidgetColumnBarItem from '../widgets/WidgetColumnBarItem.svelte';
|
import WidgetColumnBarItem from '../widgets/WidgetColumnBarItem.svelte';
|
||||||
import ColumnManager from './ColumnManager.svelte';
|
import ColumnManager from './ColumnManager.svelte';
|
||||||
@@ -11,13 +20,37 @@
|
|||||||
export let formViewComponent;
|
export let formViewComponent;
|
||||||
export let formDisplay;
|
export let formDisplay;
|
||||||
export let display;
|
export let display;
|
||||||
|
export let changeSetState;
|
||||||
|
export let dispatchChangeSet;
|
||||||
|
|
||||||
export let isDetailView = false;
|
export let isDetailView = false;
|
||||||
export let showReferences = false;
|
export let showReferences = false;
|
||||||
|
export let showMacros;
|
||||||
|
|
||||||
|
let selectedCellsPublished = [];
|
||||||
|
|
||||||
|
const selectedMacro = writable(null);
|
||||||
|
setContext('selectedMacro', selectedMacro);
|
||||||
|
const macroValues = writable({});
|
||||||
|
setContext('macroValues', macroValues);
|
||||||
|
|
||||||
let managerSize;
|
let managerSize;
|
||||||
|
|
||||||
$: isFormView = !!(formDisplay && formDisplay.config && formDisplay.config.isFormView);
|
$: isFormView = !!(formDisplay && formDisplay.config && formDisplay.config.isFormView);
|
||||||
|
|
||||||
|
const handleExecuteMacro = () => {
|
||||||
|
const newChangeSet = runMacroOnChangeSet(
|
||||||
|
$selectedMacro,
|
||||||
|
extractMacroValuesForMacro($macroValues, $selectedMacro),
|
||||||
|
selectedCellsPublished,
|
||||||
|
changeSetState?.value,
|
||||||
|
display
|
||||||
|
);
|
||||||
|
if (newChangeSet) {
|
||||||
|
dispatchChangeSet({ type: 'set', value: newChangeSet });
|
||||||
|
}
|
||||||
|
$selectedMacro = null;
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<HorizontalSplitter initialValue="300px" bind:size={managerSize}>
|
<HorizontalSplitter initialValue="300px" bind:size={managerSize}>
|
||||||
@@ -40,18 +73,36 @@
|
|||||||
>
|
>
|
||||||
<ReferenceManager {...$$props} {managerSize} />
|
<ReferenceManager {...$$props} {managerSize} />
|
||||||
</WidgetColumnBarItem>
|
</WidgetColumnBarItem>
|
||||||
|
|
||||||
|
<WidgetColumnBarItem title="Macros" name="macros" skip={!showMacros} collapsed={isDetailView}>
|
||||||
|
<MacroManager {...$$props} {managerSize} macroCondition={macro => macro.type == 'transformValue'} />
|
||||||
|
</WidgetColumnBarItem>
|
||||||
</WidgetColumnBar>
|
</WidgetColumnBar>
|
||||||
</div>
|
</div>
|
||||||
<svelte:fragment slot="2">
|
<svelte:fragment slot="2">
|
||||||
{#if isFormView}
|
<VerticalSplitter initialValue="70%" isSplitter={!!$selectedMacro && !isFormView && showMacros}>
|
||||||
<svelte:component this={formViewComponent} {...$$props} />
|
<svelte:fragment slot="1">
|
||||||
{:else}
|
{#if isFormView}
|
||||||
<svelte:component
|
<svelte:component this={formViewComponent} {...$$props} />
|
||||||
this={gridCoreComponent}
|
{:else}
|
||||||
{...$$props}
|
<svelte:component
|
||||||
formViewAvailable={!!formViewComponent && !!formDisplay}
|
this={gridCoreComponent}
|
||||||
/>
|
{...$$props}
|
||||||
{/if}
|
formViewAvailable={!!formViewComponent && !!formDisplay}
|
||||||
|
onSelectionChanged={value => (selectedCellsPublished = value)}
|
||||||
|
macroValues={extractMacroValuesForMacro($macroValues, $selectedMacro)}
|
||||||
|
macroPreview={$selectedMacro}
|
||||||
|
{selectedCellsPublished}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<svelte:fragment slot="2">
|
||||||
|
{#if $selectedMacro}
|
||||||
|
<MacroDetail onExecute={handleExecuteMacro} />
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
|
</VerticalSplitter>
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
</HorizontalSplitter>
|
</HorizontalSplitter>
|
||||||
|
|
||||||
|
|||||||
@@ -66,11 +66,26 @@
|
|||||||
export let changeSetState;
|
export let changeSetState;
|
||||||
export let dispatchChangeSet;
|
export let dispatchChangeSet;
|
||||||
|
|
||||||
|
export let macroPreview;
|
||||||
|
export let macroValues;
|
||||||
|
export let selectedCellsPublished;
|
||||||
|
|
||||||
|
// export let onChangeGrider = undefined;
|
||||||
|
|
||||||
let loadedRows = [];
|
let loadedRows = [];
|
||||||
|
|
||||||
// $: console.log('loadedRows BIND', loadedRows);
|
// $: console.log('loadedRows BIND', loadedRows);
|
||||||
$: grider = new ChangeSetGrider(loadedRows, changeSetState, dispatchChangeSet, display);
|
$: grider = new ChangeSetGrider(
|
||||||
|
loadedRows,
|
||||||
|
changeSetState,
|
||||||
|
dispatchChangeSet,
|
||||||
|
display,
|
||||||
|
macroPreview,
|
||||||
|
macroValues,
|
||||||
|
selectedCellsPublished
|
||||||
|
);
|
||||||
// $: console.log('GRIDER', grider);
|
// $: console.log('GRIDER', grider);
|
||||||
|
// $: if (onChangeGrider) onChangeGrider(grider);
|
||||||
|
|
||||||
async function handleConfirmSql(sql) {
|
async function handleConfirmSql(sql) {
|
||||||
const resp = await axiosInstance.request({
|
const resp = await axiosInstance.request({
|
||||||
@@ -162,6 +177,7 @@
|
|||||||
onOpenQuery={openQuery}
|
onOpenQuery={openQuery}
|
||||||
onOpenActiveChart={openActiveChart}
|
onOpenActiveChart={openActiveChart}
|
||||||
bind:loadedRows
|
bind:loadedRows
|
||||||
|
frameSelection={!!macroPreview}
|
||||||
{grider}
|
{grider}
|
||||||
onSave={handleSave}
|
onSave={handleSave}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -119,6 +119,7 @@
|
|||||||
{display}
|
{display}
|
||||||
{formDisplay}
|
{formDisplay}
|
||||||
showReferences
|
showReferences
|
||||||
|
showMacros
|
||||||
onReferenceSourceChanged={reference ? handleReferenceSourceChanged : null}
|
onReferenceSourceChanged={reference ? handleReferenceSourceChanged : null}
|
||||||
onReferenceClick={value => {
|
onReferenceClick={value => {
|
||||||
if (value && value.referenceId && reference && reference.referenceId == value.referenceId) {
|
if (value && value.referenceId && reference && reference.referenceId == value.referenceId) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script lang="ts" context="module">
|
<script lang="ts" context="module">
|
||||||
function extractMacroValuesForMacro(macroValues, macro) {
|
export function extractMacroValuesForMacro(macroValues, macro) {
|
||||||
// return {};
|
// return {};
|
||||||
if (!macro) return {};
|
if (!macro) return {};
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -11,11 +11,17 @@
|
|||||||
|
|
||||||
let filter = '';
|
let filter = '';
|
||||||
export let managerSize;
|
export let managerSize;
|
||||||
|
export let macroCondition;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ManagerInnerContainer width={managerSize}>
|
<ManagerInnerContainer width={managerSize}>
|
||||||
<SearchBoxWrapper>
|
<SearchBoxWrapper>
|
||||||
<SearchInput placeholder="Search macros" bind:value={filter} />
|
<SearchInput placeholder="Search macros" bind:value={filter} />
|
||||||
</SearchBoxWrapper>
|
</SearchBoxWrapper>
|
||||||
<AppObjectList list={_.sortBy(macros, 'title')} module={macroAppObject} {filter} groupFunc={data => data.group} />
|
<AppObjectList
|
||||||
|
list={_.sortBy(macros, 'title').filter(x => (macroCondition ? macroCondition(x) : true))}
|
||||||
|
module={macroAppObject}
|
||||||
|
{filter}
|
||||||
|
groupFunc={data => data.group}
|
||||||
|
/>
|
||||||
</ManagerInnerContainer>
|
</ManagerInnerContainer>
|
||||||
|
|||||||
Reference in New Issue
Block a user