configurable object actions #255

This commit is contained in:
Jan Prochazka 2022-06-09 11:31:31 +02:00
parent 610e9f4e60
commit a92bd1c840
2 changed files with 286 additions and 217 deletions

View File

@ -340,6 +340,210 @@
],
};
async function databaseObjectMenuClickHandler(data, menu) {
const getDriver = async () => {
const conn = await getConnectionInfo(data);
if (!conn) return;
const driver = findEngineDriver(conn, getExtensions());
return driver;
};
if (menu.isOpenFreeTable) {
const coninfo = await getConnectionInfo(data);
openNewTab({
title: data.pureName,
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {
initialArgs: {
functionName: 'tableReader',
props: {
connection: {
...coninfo,
database: data.database,
},
schemaName: data.schemaName,
pureName: data.pureName,
},
},
},
});
} else if (menu.isActiveChart) {
const driver = await getDriver();
const dmp = driver.createDumper();
dmp.put('^select * from %f', data);
openNewTab(
{
title: data.pureName,
icon: 'img chart',
tabComponent: 'ChartTab',
props: {
conid: data.conid,
database: data.database,
},
},
{
editor: {
config: { chartType: 'bar' },
sql: dmp.s,
},
}
);
} else if (menu.isQueryDesigner) {
openNewTab(
{
title: 'Query #',
icon: 'img query-design',
tabComponent: 'QueryDesignTab',
props: {
conid: data.conid,
database: data.database,
},
},
{
editor: {
tables: [
{
...data,
designerId: uuidv1(),
left: 50,
top: 50,
},
],
},
}
);
} else if (menu.isDiagram) {
openNewTab(
{
title: 'Diagram #',
icon: 'img diagram',
tabComponent: 'DiagramTab',
props: {
conid: data.conid,
database: data.database,
},
},
{
editor: {
tables: [
{
...data,
designerId: `${data.pureName}-${uuidv1()}`,
autoAddReferences: true,
},
],
references: [],
autoLayout: true,
},
}
);
} else if (menu.sqlGeneratorProps) {
showModal(SqlGeneratorModal, {
initialObjects: [data],
initialConfig: menu.sqlGeneratorProps,
conid: data.conid,
database: data.database,
});
} else if (menu.isDrop) {
const { conid, database } = data;
alterDatabaseDialog(conid, database, db => {
_.remove(
db[data.objectTypeField] as any[],
x => x.schemaName == data.schemaName && x.pureName == data.pureName
);
});
} else if (menu.isRename) {
const { conid, database } = data;
renameDatabaseObjectDialog(conid, database, data.pureName, (db, newName) => {
const obj = db[data.objectTypeField].find(x => x.schemaName == data.schemaName && x.pureName == data.pureName);
obj.pureName = newName;
});
} else if (menu.isDropCollection) {
showModal(ConfirmModal, {
message: `Really drop collection ${data.pureName}?`,
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
await apiCall('database-connections/run-script', {
...dbid,
sql: `db.dropCollection('${data.pureName}')`,
});
apiCall('database-connections/sync-model', dbid);
},
});
} else if (menu.isRenameCollection) {
showModal(InputTextModal, {
label: 'New collection name',
header: 'Rename collection',
value: data.pureName,
onConfirm: async newName => {
const dbid = _.pick(data, ['conid', 'database']);
await apiCall('database-connections/run-script', {
...dbid,
sql: `db.renameCollection('${data.pureName}', '${newName}')`,
});
apiCall('database-connections/sync-model', dbid);
},
});
} else if (menu.isDuplicateTable) {
const driver = await getDriver();
const dmp = driver.createDumper();
const newTable = _.cloneDeep(data);
const { conid, database } = data;
newTable.pureName = `_${newTable.pureName}_${dateFormat(new Date(), 'yyyy-MM-dd-hh-mm-ss')}`;
newTable.columns.forEach(x => {
x.autoIncrement = false;
x.defaultConstraint = null;
});
newTable.foreignKeys = [];
newTable.checks = [];
newTable.uniques = [];
newTable.indexes = [];
if (newTable.primaryKey) {
newTable.primaryKey.constraintName = null;
}
dmp.createTable(newTable);
dmp.putCmd(
'^insert ^into %f(%,i) ^select %,i from %f',
newTable,
newTable.columns.map(x => x.columnName),
data.columns.map(x => x.columnName),
data
);
showModal(ConfirmSqlModal, {
sql: dmp.s,
onConfirm: async () => {
const resp = await apiCall('database-connections/run-script', { conid, database, sql: dmp.s });
await apiCall('database-connections/sync-model', { conid, database });
},
engine: driver.engine,
});
} else if (menu.isImport) {
const { conid, database } = data;
showModal(ImportExportModal, {
initialValues: {
sourceStorageType: getDefaultFileFormat(getExtensions()).storageType,
targetStorageType: 'database',
targetConnectionId: conid,
targetDatabaseName: database,
fixedTargetPureName: data.pureName,
},
});
} else {
openDatabaseObjectDetail(
menu.tab,
menu.scriptTemplate,
data,
menu.forceNewTab,
menu.initialData,
menu.icon,
data
);
}
}
export async function openDatabaseObjectDetail(
tabComponent,
scriptTemplate,
@ -380,6 +584,13 @@
export function handleDatabaseObjectClick(data, forceNewTab = false) {
const { schemaName, pureName, conid, database, objectTypeField } = data;
const configuredAction = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`];
const overrideMenu = menus[objectTypeField].find(x => x.label && x.label == configuredAction);
if (overrideMenu) {
databaseObjectMenuClickHandler(data, overrideMenu);
return;
}
openDatabaseObjectDetail(
defaultTabs[objectTypeField],
defaultTabs[objectTypeField] ? null : 'CREATE OBJECT',
@ -408,13 +619,6 @@
}
export function createDatabaseObjectMenu(data) {
const getDriver = async () => {
const conn = await getConnectionInfo(data);
if (!conn) return;
const driver = findEngineDriver(conn, getExtensions());
return driver;
};
const { objectTypeField } = data;
return menus[objectTypeField]
.filter(x => x)
@ -455,203 +659,8 @@
return {
text: menu.label,
onClick: async () => {
if (menu.isOpenFreeTable) {
const coninfo = await getConnectionInfo(data);
openNewTab({
title: data.pureName,
icon: 'img free-table',
tabComponent: 'FreeTableTab',
props: {
initialArgs: {
functionName: 'tableReader',
props: {
connection: {
...coninfo,
database: data.database,
},
schemaName: data.schemaName,
pureName: data.pureName,
},
},
},
});
} else if (menu.isActiveChart) {
const driver = await getDriver();
const dmp = driver.createDumper();
dmp.put('^select * from %f', data);
openNewTab(
{
title: data.pureName,
icon: 'img chart',
tabComponent: 'ChartTab',
props: {
conid: data.conid,
database: data.database,
},
},
{
editor: {
config: { chartType: 'bar' },
sql: dmp.s,
},
}
);
} else if (menu.isQueryDesigner) {
openNewTab(
{
title: 'Query #',
icon: 'img query-design',
tabComponent: 'QueryDesignTab',
props: {
conid: data.conid,
database: data.database,
},
},
{
editor: {
tables: [
{
...data,
designerId: uuidv1(),
left: 50,
top: 50,
},
],
},
}
);
} else if (menu.isDiagram) {
openNewTab(
{
title: 'Diagram #',
icon: 'img diagram',
tabComponent: 'DiagramTab',
props: {
conid: data.conid,
database: data.database,
},
},
{
editor: {
tables: [
{
...data,
designerId: `${data.pureName}-${uuidv1()}`,
autoAddReferences: true,
},
],
references: [],
autoLayout: true,
},
}
);
} else if (menu.sqlGeneratorProps) {
showModal(SqlGeneratorModal, {
initialObjects: [data],
initialConfig: menu.sqlGeneratorProps,
conid: data.conid,
database: data.database,
});
} else if (menu.isDrop) {
const { conid, database } = data;
alterDatabaseDialog(conid, database, db => {
_.remove(
db[data.objectTypeField] as any[],
x => x.schemaName == data.schemaName && x.pureName == data.pureName
);
});
} else if (menu.isRename) {
const { conid, database } = data;
renameDatabaseObjectDialog(conid, database, data.pureName, (db, newName) => {
const obj = db[data.objectTypeField].find(
x => x.schemaName == data.schemaName && x.pureName == data.pureName
);
obj.pureName = newName;
});
} else if (menu.isDropCollection) {
showModal(ConfirmModal, {
message: `Really drop collection ${data.pureName}?`,
onConfirm: async () => {
const dbid = _.pick(data, ['conid', 'database']);
await apiCall('database-connections/run-script', {
...dbid,
sql: `db.dropCollection('${data.pureName}')`,
});
apiCall('database-connections/sync-model', dbid);
},
});
} else if (menu.isRenameCollection) {
showModal(InputTextModal, {
label: 'New collection name',
header: 'Rename collection',
value: data.pureName,
onConfirm: async newName => {
const dbid = _.pick(data, ['conid', 'database']);
await apiCall('database-connections/run-script', {
...dbid,
sql: `db.renameCollection('${data.pureName}', '${newName}')`,
});
apiCall('database-connections/sync-model', dbid);
},
});
} else if (menu.isDuplicateTable) {
const driver = await getDriver();
const dmp = driver.createDumper();
const newTable = _.cloneDeep(data);
const { conid, database } = data;
newTable.pureName = `_${newTable.pureName}_${dateFormat(new Date(), 'yyyy-MM-dd-hh-mm-ss')}`;
newTable.columns.forEach(x => {
x.autoIncrement = false;
x.defaultConstraint = null;
});
newTable.foreignKeys = [];
newTable.checks = [];
newTable.uniques = [];
newTable.indexes = [];
if (newTable.primaryKey) {
newTable.primaryKey.constraintName = null;
}
dmp.createTable(newTable);
dmp.putCmd(
'^insert ^into %f(%,i) ^select %,i from %f',
newTable,
newTable.columns.map(x => x.columnName),
data.columns.map(x => x.columnName),
data
);
showModal(ConfirmSqlModal, {
sql: dmp.s,
onConfirm: async () => {
const resp = await apiCall('database-connections/run-script', { conid, database, sql: dmp.s });
await apiCall('database-connections/sync-model', { conid, database });
},
engine: driver.engine,
});
} else if (menu.isImport) {
const { conid, database } = data;
showModal(ImportExportModal, {
initialValues: {
sourceStorageType: getDefaultFileFormat(getExtensions()).storageType,
targetStorageType: 'database',
targetConnectionId: conid,
targetDatabaseName: database,
fixedTargetPureName: data.pureName,
},
});
} else {
openDatabaseObjectDetail(
menu.tab,
menu.scriptTemplate,
data,
menu.forceNewTab,
menu.initialData,
menu.icon,
data
);
}
onClick: () => {
databaseObjectMenuClickHandler(data, menu);
},
};
});
@ -671,7 +680,14 @@
<script lang="ts">
import _ from 'lodash';
import AppObjectCore from './AppObjectCore.svelte';
import { currentDatabase, extensions, getExtensions, openedConnections, pinnedTables } from '../stores';
import {
currentDatabase,
extensions,
getCurrentSettings,
getExtensions,
openedConnections,
pinnedTables,
} from '../stores';
import openNewTab from '../utility/openNewTab';
import { filterName, generateDbPairingId, getAlterDatabaseScript } from 'dbgate-tools';
import { getConnectionInfo, getDatabaseInfo } from '../utility/metadataLoaders';

View File

@ -60,6 +60,7 @@ ORDER BY
tabs={[
{ label: 'General', slot: 1 },
{ label: 'Themes', slot: 2 },
{ label: 'Actions', slot: 3 },
]}
>
<svelte:fragment slot="1">
@ -102,18 +103,6 @@ ORDER BY
defaultValue="30"
disabled={values['connection.autoRefresh'] === false}
/>
<div class="heading">Default actions</div>
<FormSelectField
label="Connection click"
name="defaultAction.connectionClick"
isNative
defaultValue='openDetails'
options={[
{ value: 'openDetails', label: 'Edit / open details' },
{ value: 'connect', label: 'Connect' },
]}
/>
</svelte:fragment>
<svelte:fragment slot="2">
<div class="heading">Application theme</div>
@ -161,6 +150,70 @@ ORDER BY
<SqlEditor value={sqlPreview} readOnly />
</div>
</svelte:fragment>
<svelte:fragment slot="3">
<div class="heading">Default actions</div>
<FormSelectField
label="Connection click"
name="defaultAction.connectionClick"
isNative
defaultValue="openDetails"
options={[
{ value: 'openDetails', label: 'Edit / open details' },
{ value: 'connect', label: 'Connect' },
]}
/>
<FormSelectField
label="Table click"
name="defaultAction.dbObjectClick.tables"
isNative
defaultValue=""
options={[
{ value: '', label: 'Open data, or open existing' },
{ value: 'Open data', label: 'Open data (always new tab)' },
{ value: 'Open form', label: 'Open form (always new tab)' },
{ value: 'Open structure', label: 'Open structure' },
{ value: 'SQL: CREATE TABLE', label: 'SQL: CREATE' },
{ value: 'SQL: SELECT', label: 'SQL: SELECT' },
]}
/>
<FormSelectField
label="View click"
name="defaultAction.dbObjectClick.views"
isNative
defaultValue=""
options={[
{ value: '', label: 'Open data, or open existing' },
{ value: 'Open data', label: 'Open data (always new tab)' },
{ value: 'SQL: CREATE VIEW', label: 'SQL: CREATE' },
]}
/>
<FormSelectField
label="Materialized view click"
name="defaultAction.dbObjectClick.matviews"
isNative
defaultValue=""
options={[
{ value: '', label: 'Open data, or open existing' },
{ value: 'Open data', label: 'Open data (always new tab)' },
{ value: 'SQL: CREATE MATERIALIZED VIEW', label: 'SQL: CREATE' },
]}
/>
<FormSelectField
label="Procedure click"
name="defaultAction.dbObjectClick.procedures"
isNative
defaultValue=""
options={[
{ value: '', label: 'SQL: CREATE' },
{ value: 'SQL: EXECUTE', label: 'SQL: EXECUTE' },
// { value: 'SQL: CREATE PROCEDURE', label: 'SQL: CREATE' },
]}
/>
</svelte:fragment>
</TabControl>
</FormValues>