mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-24 15:15:59 +00:00
fixed TS + code tidy
This commit is contained in:
49
packages/web/src/macro/MacroDetail.svelte
Normal file
49
packages/web/src/macro/MacroDetail.svelte
Normal file
@@ -0,0 +1,49 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import TabControl from '../elements/TabControl.svelte';
|
||||
import AceEditor from '../query/AceEditor.svelte';
|
||||
|
||||
import MacroHeader from './MacroHeader.svelte';
|
||||
import MacroInfoTab from './MacroInfoTab.svelte';
|
||||
|
||||
const selectedMacro = getContext('selectedMacro') as any;
|
||||
|
||||
export let onExecute;
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<MacroHeader {onExecute} />
|
||||
<TabControl
|
||||
tabs={[
|
||||
{
|
||||
label: 'Macro detail',
|
||||
component: MacroInfoTab,
|
||||
props: {
|
||||
onExecute,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'JavaScript',
|
||||
component: AceEditor,
|
||||
props: {
|
||||
readOnly: true,
|
||||
value: $selectedMacro?.code,
|
||||
mode: 'javascript',
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
</style>
|
||||
48
packages/web/src/macro/MacroHeader.svelte
Normal file
48
packages/web/src/macro/MacroHeader.svelte
Normal file
@@ -0,0 +1,48 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
import FontIcon from '../icons/FontIcon.svelte';
|
||||
import ToolbarButton from '../buttons/ToolbarButton.svelte';
|
||||
|
||||
export let onExecute;
|
||||
|
||||
const selectedMacro = getContext('selectedMacro') as any;
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<FontIcon icon="img macro" />
|
||||
<div class="ml-2">
|
||||
{$selectedMacro?.title}
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<ToolbarButton icon="icon run" on:click={onExecute}>Execute</ToolbarButton>
|
||||
<ToolbarButton icon="icon close" on:click={() => ($selectedMacro = null)}>Close</ToolbarButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
background: var(--theme-bg-modalheader);
|
||||
height: var(--dim-toolbar-height);
|
||||
min-height: var(--dim-toolbar-height);
|
||||
overflow: hidden;
|
||||
border-top: 1px solid var(--theme-border);
|
||||
border-bottom: 1px solid var(--theme-border);
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: bold;
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
</style>
|
||||
45
packages/web/src/macro/MacroInfoTab.svelte
Normal file
45
packages/web/src/macro/MacroInfoTab.svelte
Normal file
@@ -0,0 +1,45 @@
|
||||
<script lang="ts">
|
||||
import { getContext } from 'svelte';
|
||||
|
||||
import FormStyledButton from '../buttons/FormStyledButton.svelte';
|
||||
|
||||
import WidgetTitle from '../widgets/WidgetTitle.svelte';
|
||||
import MacroParameters from './MacroParameters.svelte';
|
||||
|
||||
const selectedMacro = getContext('selectedMacro') as any;
|
||||
|
||||
export let onExecute;
|
||||
</script>
|
||||
|
||||
<div class="wrapper">
|
||||
<div class="section">
|
||||
<WidgetTitle>Execute</WidgetTitle>
|
||||
<FormStyledButton value="Execute" on:click={onExecute} />
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<WidgetTitle>Parameters</WidgetTitle>
|
||||
{#if $selectedMacro?.args && $selectedMacro?.args?.length > 0}
|
||||
{#key $selectedMacro?.name}
|
||||
<MacroParameters args={$selectedMacro?.args||[]} namePrefix={`${$selectedMacro?.name}#`} />
|
||||
{/key}
|
||||
{:else}
|
||||
<div class="m-1">This macro has no parameters</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<WidgetTitle>Description</WidgetTitle>
|
||||
<div class="m-1">{$selectedMacro?.description}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.section {
|
||||
margin: 5px;
|
||||
}
|
||||
</style>
|
||||
27
packages/web/src/macro/MacroManager.svelte
Normal file
27
packages/web/src/macro/MacroManager.svelte
Normal file
@@ -0,0 +1,27 @@
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
|
||||
import AppObjectList from '../appobj/AppObjectList.svelte';
|
||||
import * as macroAppObject from '../appobj/MacroAppObject.svelte';
|
||||
|
||||
import ManagerInnerContainer from '../elements/ManagerInnerContainer.svelte';
|
||||
import SearchBoxWrapper from '../elements/SearchBoxWrapper.svelte';
|
||||
import SearchInput from '../elements/SearchInput.svelte';
|
||||
import macros from './macros';
|
||||
|
||||
let filter = '';
|
||||
export let managerSize;
|
||||
export let macroCondition;
|
||||
</script>
|
||||
|
||||
<ManagerInnerContainer width={managerSize}>
|
||||
<SearchBoxWrapper>
|
||||
<SearchInput placeholder="Search macros" bind:value={filter} />
|
||||
</SearchBoxWrapper>
|
||||
<AppObjectList
|
||||
list={_.sortBy(macros, 'title').filter(x => (macroCondition ? macroCondition(x) : true))}
|
||||
module={macroAppObject}
|
||||
{filter}
|
||||
groupFunc={data => data.group}
|
||||
/>
|
||||
</ManagerInnerContainer>
|
||||
26
packages/web/src/macro/MacroParameters.svelte
Normal file
26
packages/web/src/macro/MacroParameters.svelte
Normal file
@@ -0,0 +1,26 @@
|
||||
<script lang="ts">
|
||||
import _ from 'lodash';
|
||||
import { getContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import FormArgumentList from '../forms/FormArgumentList.svelte';
|
||||
import FormProviderCore from '../forms/FormProviderCore.svelte';
|
||||
import FormFieldTemplateRow from '../forms/FormFieldTemplateRow.svelte';
|
||||
|
||||
export let args = [];
|
||||
const macroValues = getContext('macroValues');
|
||||
export let namePrefix;
|
||||
// export let onChangeValues;
|
||||
|
||||
// const initialValues = {
|
||||
// ..._.fromPairs(args.filter(x => x.default != null).map(x => [`${namePrefix}${x.name}`, x.default])),
|
||||
// ...macroValues,
|
||||
// };
|
||||
|
||||
// const values = writable(initialValues);
|
||||
|
||||
// $: if (onChangeValues) onChangeValues($values);
|
||||
</script>
|
||||
|
||||
<FormProviderCore values={macroValues} template={FormFieldTemplateRow}>
|
||||
<FormArgumentList {args} {namePrefix} />
|
||||
</FormProviderCore>
|
||||
42
packages/web/src/macro/MacroPreviewGrider.ts
Normal file
42
packages/web/src/macro/MacroPreviewGrider.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import type { FreeTableModel, MacroDefinition, MacroSelectedCell } from 'dbgate-datalib';
|
||||
import { runMacro } from 'dbgate-datalib';
|
||||
import Grider from '../datagrid/Grider';
|
||||
import type { GriderRowStatus } from '../datagrid/Grider';
|
||||
import _ from 'lodash';
|
||||
|
||||
function convertToSet(row, field) {
|
||||
if (!row) return null;
|
||||
if (!row[field]) return null;
|
||||
if (_.isSet(row[field])) return row[field];
|
||||
return new Set(row[field]);
|
||||
}
|
||||
|
||||
export default class MacroPreviewGrider extends Grider {
|
||||
model: FreeTableModel;
|
||||
_errors: string[] = [];
|
||||
constructor(model: FreeTableModel, macro: MacroDefinition, macroArgs: {}, selectedCells: MacroSelectedCell[]) {
|
||||
super();
|
||||
this.model = runMacro(macro, macroArgs, model, true, selectedCells, this._errors);
|
||||
}
|
||||
|
||||
get errors() {
|
||||
return this._errors;
|
||||
}
|
||||
|
||||
getRowStatus(index): GriderRowStatus {
|
||||
const row = this.model.rows[index];
|
||||
return {
|
||||
status: (row && row.__rowStatus) || 'regular',
|
||||
modifiedFields: convertToSet(row, '__modifiedFields'),
|
||||
insertedFields: convertToSet(row, '__insertedFields'),
|
||||
deletedFields: convertToSet(row, '__deletedFields'),
|
||||
};
|
||||
}
|
||||
|
||||
getRowData(index: any) {
|
||||
return this.model.rows[index];
|
||||
}
|
||||
get rowCount() {
|
||||
return this.model.rows.length;
|
||||
}
|
||||
}
|
||||
352
packages/web/src/macro/macros.js
Normal file
352
packages/web/src/macro/macros.js
Normal file
@@ -0,0 +1,352 @@
|
||||
const macros = [
|
||||
{
|
||||
title: 'Remove diacritics',
|
||||
name: 'removeDiacritics',
|
||||
group: 'Text',
|
||||
description: 'Removes diacritics from selected cells',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.deburr(value)`,
|
||||
},
|
||||
{
|
||||
title: 'Search & replace text',
|
||||
name: 'stringReplace',
|
||||
group: 'Text',
|
||||
description: 'Search & replace text or regular expression',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Find',
|
||||
name: 'find',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Replace with',
|
||||
name: 'replace',
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Case sensitive',
|
||||
name: 'caseSensitive',
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: 'Regular expression',
|
||||
name: 'isRegex',
|
||||
},
|
||||
],
|
||||
code: `
|
||||
const rtext = args.isRegex ? args.find : modules.lodash.escapeRegExp(args.find);
|
||||
const rflags = args.caseSensitive ? 'g' : 'ig';
|
||||
return value ? value.toString().replace(new RegExp(rtext, rflags), args.replace || '') : value
|
||||
`,
|
||||
},
|
||||
{
|
||||
title: 'Change text case',
|
||||
name: 'changeTextCase',
|
||||
group: 'Text',
|
||||
description: 'Uppercase, lowercase and other case functions',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'select',
|
||||
options: ['toUpper', 'toLower', 'lowerCase', 'upperCase', 'kebabCase', 'snakeCase', 'camelCase', 'startCase'],
|
||||
label: 'Type',
|
||||
name: 'type',
|
||||
default: 'toUpper',
|
||||
},
|
||||
],
|
||||
code: `return modules.lodash[args.type](value)`,
|
||||
},
|
||||
{
|
||||
title: 'Pad left',
|
||||
name: 'padLeft',
|
||||
group: 'Text',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Character',
|
||||
name: 'character',
|
||||
default: '0',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Length',
|
||||
name: 'length',
|
||||
default: '3',
|
||||
},
|
||||
],
|
||||
description:
|
||||
'Returns string of a specified length in which the beginning of the current string is padded with spaces or other character',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.padStart(value, +args.length, args.character)`,
|
||||
},
|
||||
{
|
||||
title: 'Pad right',
|
||||
name: 'padRight',
|
||||
group: 'Text',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Character',
|
||||
name: 'character',
|
||||
default: '0',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Length',
|
||||
name: 'length',
|
||||
default: '3',
|
||||
},
|
||||
],
|
||||
description:
|
||||
'Returns string of a specified length in which the end of the current string is padded with spaces or other character',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.padEnd(value, +args.length, args.character)`,
|
||||
},
|
||||
{
|
||||
title: 'Trim',
|
||||
name: 'trim',
|
||||
group: 'Text',
|
||||
description: 'Removes leading and trailing whitespace ',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.trim(value)`,
|
||||
},
|
||||
{
|
||||
title: 'Row index',
|
||||
name: 'rowIndex',
|
||||
group: 'Tools',
|
||||
description: 'Index of row from 1 (autoincrement)',
|
||||
type: 'transformValue',
|
||||
code: `return rowIndex + 1`,
|
||||
},
|
||||
{
|
||||
title: 'Generate UUID',
|
||||
name: 'uuidv1',
|
||||
group: 'Tools',
|
||||
description: 'Generate unique identifier',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'select',
|
||||
options: [
|
||||
{ value: 'uuidv1', name: 'V1 - from timestamp' },
|
||||
{ value: 'uuidv4', name: 'V4 - random generated' },
|
||||
],
|
||||
label: 'Version',
|
||||
name: 'version',
|
||||
default: 'uuidv1',
|
||||
},
|
||||
],
|
||||
code: `return modules[args.version]()`,
|
||||
},
|
||||
{
|
||||
title: 'Convert to integer',
|
||||
name: 'toInt',
|
||||
group: 'Tools',
|
||||
description: 'Converts to integral number',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.isNaN(parseInt(value)) ? null : parseInt(value)`,
|
||||
},
|
||||
{
|
||||
title: 'Convert to number',
|
||||
name: 'toNumber',
|
||||
group: 'Tools',
|
||||
description: 'Converts to number',
|
||||
type: 'transformValue',
|
||||
code: `return modules.lodash.isNaN(parseFloat(value)) ? null : parseFloat(value)`,
|
||||
},
|
||||
{
|
||||
title: 'Convert to boolean',
|
||||
name: 'toBoolean',
|
||||
group: 'Tools',
|
||||
description: 'Converts to boolean',
|
||||
type: 'transformValue',
|
||||
code: `
|
||||
if (modules.lodash.isString(value)) {
|
||||
if (value.toLowerCase()=='true') return true;
|
||||
if (value.toLowerCase()=='false') return false;
|
||||
if (value == '1') return true;
|
||||
if (value == '0') return false;
|
||||
if (value.toLowerCase()=='t') return true;
|
||||
if (value.toLowerCase()=='f') return false;
|
||||
}
|
||||
if (value==null) return null;
|
||||
return !!value;
|
||||
`,
|
||||
},
|
||||
{
|
||||
title: 'Convert to string',
|
||||
name: 'toString',
|
||||
group: 'Tools',
|
||||
description: 'Converts to string',
|
||||
type: 'transformValue',
|
||||
code: `
|
||||
if (value==null) return null;
|
||||
if (value && value.$oid) return value.$oid;
|
||||
return value.toString();
|
||||
`,
|
||||
},
|
||||
{
|
||||
title: 'Current date',
|
||||
name: 'currentDate',
|
||||
group: 'Tools',
|
||||
description: 'Gets current date',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Format',
|
||||
name: 'format',
|
||||
default: 'YYYY-MM-DD HH:mm:ss',
|
||||
},
|
||||
],
|
||||
code: `return modules.moment().format(args.format)`,
|
||||
},
|
||||
{
|
||||
title: 'Duplicate columns',
|
||||
name: 'duplicateColumns',
|
||||
group: 'Tools',
|
||||
description: 'Duplicate selected columns',
|
||||
type: 'transformRow',
|
||||
code: `
|
||||
return {
|
||||
...row,
|
||||
...modules.lodash.fromPairs(columns.map(col=>[(args.prefix || '') + col + (args.postfix || ''), row[col]]))
|
||||
}
|
||||
`,
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Prefix',
|
||||
name: 'prefix',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Postfix',
|
||||
name: 'postfix',
|
||||
default: '_copy',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Split columns',
|
||||
name: 'splitColumns',
|
||||
group: 'Tools',
|
||||
description: 'Split selected columns',
|
||||
type: 'transformRow',
|
||||
code: `
|
||||
const res = {...row};
|
||||
for(const col of columns) {
|
||||
const value = row[col];
|
||||
if (modules.lodash.isString(value)) {
|
||||
const splitted = value.split(args.delimiter);
|
||||
splitted.forEach((splitValue, valueIndex) => {
|
||||
const name = col + '_' + (valueIndex + 1).toString();
|
||||
res[name] = splitValue;
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
`,
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Delimiter',
|
||||
name: 'delimiter',
|
||||
default: ',',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: 'Calculation',
|
||||
name: 'calculation',
|
||||
group: 'Tools',
|
||||
description: 'Custom expression. Use row.column_name for accessing column values, value for original value',
|
||||
type: 'transformValue',
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Expression',
|
||||
name: 'expression',
|
||||
default: 'value',
|
||||
},
|
||||
],
|
||||
code: `return eval(args.expression);`,
|
||||
},
|
||||
{
|
||||
title: 'Extract date fields',
|
||||
name: 'extractDateFields',
|
||||
group: 'Tools',
|
||||
description: 'Extract yaear, month, day and other date/time fields from selection and adds it as new columns',
|
||||
type: 'transformRow',
|
||||
code: `
|
||||
let mom = null;
|
||||
for(const col of columns) {
|
||||
const m = modules.moment(row[col]);
|
||||
if (m.isValid()) {
|
||||
mom = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mom) return row;
|
||||
|
||||
const addedColumnNames = modules.lodash.compact([args.year, args.month, args.day, args.hour, args.minute, args.second]);
|
||||
|
||||
const fields = {
|
||||
[args.year]: mom.year(),
|
||||
[args.month]: mom.month() + 1,
|
||||
[args.day]: mom.day(),
|
||||
[args.hour]: mom.hour(),
|
||||
[args.minute]: mom.minute(),
|
||||
[args.second]: mom.second(),
|
||||
};
|
||||
|
||||
return {
|
||||
...row,
|
||||
...modules.lodash.pick(fields, addedColumnNames),
|
||||
};
|
||||
`,
|
||||
args: [
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Year name',
|
||||
name: 'year',
|
||||
default: 'year',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Month name',
|
||||
name: 'month',
|
||||
default: 'month',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Day name',
|
||||
name: 'day',
|
||||
default: 'day',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Hour name',
|
||||
name: 'hour',
|
||||
default: 'hour',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Minute name',
|
||||
name: 'minute',
|
||||
default: 'minute',
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
label: 'Second name',
|
||||
name: 'second',
|
||||
default: 'second',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default macros;
|
||||
Reference in New Issue
Block a user