mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-30 22:03:58 +00:00
Merge branch 'feature/tab-preview-mode'
This commit is contained in:
@@ -14,6 +14,7 @@
|
|||||||
export let module = null;
|
export let module = null;
|
||||||
|
|
||||||
export let isBold = false;
|
export let isBold = false;
|
||||||
|
export let isChoosed = false;
|
||||||
export let isBusy = false;
|
export let isBusy = false;
|
||||||
export let statusIcon = undefined;
|
export let statusIcon = undefined;
|
||||||
export let statusIconBefore = undefined;
|
export let statusIconBefore = undefined;
|
||||||
@@ -66,11 +67,21 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// $: console.log(title, indentLevel);
|
// $: console.log(title, indentLevel);
|
||||||
|
let domDiv;
|
||||||
|
|
||||||
|
$: if (isBold && domDiv) {
|
||||||
|
domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
||||||
|
}
|
||||||
|
|
||||||
|
$: if (isChoosed && domDiv) {
|
||||||
|
domDiv.scrollIntoView({ block: 'nearest', inline: 'nearest' });
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="main"
|
class="main"
|
||||||
class:isBold
|
class:isBold
|
||||||
|
class:isChoosed
|
||||||
draggable={true}
|
draggable={true}
|
||||||
on:click={handleClick}
|
on:click={handleClick}
|
||||||
on:mouseup={handleMouseUp}
|
on:mouseup={handleMouseUp}
|
||||||
@@ -83,6 +94,7 @@
|
|||||||
on:dragenter
|
on:dragenter
|
||||||
on:dragend
|
on:dragend
|
||||||
on:drop
|
on:drop
|
||||||
|
bind:this={domDiv}
|
||||||
>
|
>
|
||||||
{#if checkedObjectsStore}
|
{#if checkedObjectsStore}
|
||||||
<CheckboxField
|
<CheckboxField
|
||||||
@@ -180,6 +192,12 @@
|
|||||||
.isBold {
|
.isBold {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
.isChoosed {
|
||||||
|
background-color: var(--theme-bg-3);
|
||||||
|
}
|
||||||
|
:global(.app-object-list-focused) .isChoosed {
|
||||||
|
background-color: var(--theme-bg-selected);
|
||||||
|
}
|
||||||
.status {
|
.status {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
export let emptyGroupNames = [];
|
export let emptyGroupNames = [];
|
||||||
|
|
||||||
export let collapsedGroupNames = writable([]);
|
export let collapsedGroupNames = writable([]);
|
||||||
|
export let onChangeFilteredList;
|
||||||
|
|
||||||
$: filtered = !groupFunc
|
$: filtered = !groupFunc
|
||||||
? list.filter(data => {
|
? list.filter(data => {
|
||||||
|
|||||||
@@ -509,9 +509,9 @@ await dbgateApi.dropAllDbObjects(${JSON.stringify(
|
|||||||
extInfo={data.extInfo}
|
extInfo={data.extInfo}
|
||||||
icon="img database"
|
icon="img database"
|
||||||
colorMark={passProps?.connectionColorFactory &&
|
colorMark={passProps?.connectionColorFactory &&
|
||||||
passProps?.connectionColorFactory({ conid: _.get(data.connection, '_id'), database: data.name }, null, null, false)}
|
passProps?.connectionColorFactory({ conid: data?.connection?._id, database: data.name }, null, null, false)}
|
||||||
isBold={_.get($currentDatabase, 'connection._id') == _.get(data.connection, '_id') &&
|
isBold={$currentDatabase?.connection?._id == data?.connection?._id &&
|
||||||
extractDbNameFromComposite(_.get($currentDatabase, 'name')) == data.name}
|
extractDbNameFromComposite($currentDatabase?.name) == data.name}
|
||||||
on:click={() => switchCurrentDatabase(data)}
|
on:click={() => switchCurrentDatabase(data)}
|
||||||
on:dragstart
|
on:dragstart
|
||||||
on:dragenter
|
on:dragenter
|
||||||
|
|||||||
@@ -29,12 +29,18 @@
|
|||||||
views: 'ViewDataTab',
|
views: 'ViewDataTab',
|
||||||
matviews: 'ViewDataTab',
|
matviews: 'ViewDataTab',
|
||||||
queries: 'QueryDataTab',
|
queries: 'QueryDataTab',
|
||||||
|
procedures: 'SqlObjectTab',
|
||||||
|
functions: 'SqlObjectTab',
|
||||||
};
|
};
|
||||||
|
|
||||||
function createMenusCore(
|
function createScriptTemplatesSubmenu(objectTypeField) {
|
||||||
objectTypeField,
|
return {
|
||||||
driver
|
label: 'SQL template',
|
||||||
): {
|
submenu: getSupportedScriptTemplates(objectTypeField),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DbObjMenuItem {
|
||||||
label?: string;
|
label?: string;
|
||||||
tab?: string;
|
tab?: string;
|
||||||
forceNewTab?: boolean;
|
forceNewTab?: boolean;
|
||||||
@@ -53,34 +59,22 @@
|
|||||||
isExport?: boolean;
|
isExport?: boolean;
|
||||||
isImport?: boolean;
|
isImport?: boolean;
|
||||||
isActiveChart?: boolean;
|
isActiveChart?: boolean;
|
||||||
|
isShowSql?: boolean;
|
||||||
scriptTemplate?: string;
|
scriptTemplate?: string;
|
||||||
sqlGeneratorProps?: any;
|
sqlGeneratorProps?: any;
|
||||||
isDropCollection?: boolean;
|
isDropCollection?: boolean;
|
||||||
isRenameCollection?: boolean;
|
isRenameCollection?: boolean;
|
||||||
isDuplicateCollection?: boolean;
|
isDuplicateCollection?: boolean;
|
||||||
}[] {
|
submenu?: DbObjMenuItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMenusCore(objectTypeField, driver): DbObjMenuItem[] {
|
||||||
switch (objectTypeField) {
|
switch (objectTypeField) {
|
||||||
case 'tables':
|
case 'tables':
|
||||||
return [
|
return [
|
||||||
|
...defaultDatabaseObjectAppObjectActions['tables'],
|
||||||
{
|
{
|
||||||
label: 'Open data',
|
divider: true,
|
||||||
tab: 'TableDataTab',
|
|
||||||
forceNewTab: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Open form',
|
|
||||||
tab: 'TableDataTab',
|
|
||||||
forceNewTab: true,
|
|
||||||
initialData: {
|
|
||||||
grid: {
|
|
||||||
isFormView: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Open structure',
|
|
||||||
tab: 'TableStructureTab',
|
|
||||||
icon: 'img table-structure',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Design query',
|
label: 'Design query',
|
||||||
@@ -93,6 +87,33 @@
|
|||||||
forceNewTab: true,
|
forceNewTab: true,
|
||||||
icon: 'img perspective',
|
icon: 'img perspective',
|
||||||
},
|
},
|
||||||
|
createScriptTemplatesSubmenu('tables'),
|
||||||
|
{
|
||||||
|
label: 'SQL generator',
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: 'CREATE TABLE',
|
||||||
|
sqlGeneratorProps: {
|
||||||
|
createTables: true,
|
||||||
|
createIndexes: true,
|
||||||
|
createForeignKeys: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'DROP TABLE',
|
||||||
|
sqlGeneratorProps: {
|
||||||
|
dropTables: true,
|
||||||
|
dropReferences: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'INSERT',
|
||||||
|
sqlGeneratorProps: {
|
||||||
|
insert: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
divider: true,
|
divider: true,
|
||||||
},
|
},
|
||||||
@@ -142,50 +163,12 @@
|
|||||||
label: 'Open active chart',
|
label: 'Open active chart',
|
||||||
isActiveChart: true,
|
isActiveChart: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: CREATE TABLE',
|
|
||||||
scriptTemplate: 'CREATE TABLE',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: SELECT',
|
|
||||||
scriptTemplate: 'SELECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: CREATE TABLE',
|
|
||||||
sqlGeneratorProps: {
|
|
||||||
createTables: true,
|
|
||||||
createIndexes: true,
|
|
||||||
createForeignKeys: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: DROP TABLE',
|
|
||||||
sqlGeneratorProps: {
|
|
||||||
dropTables: true,
|
|
||||||
dropReferences: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: INSERT',
|
|
||||||
sqlGeneratorProps: {
|
|
||||||
insert: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
case 'views':
|
case 'views':
|
||||||
return [
|
return [
|
||||||
|
...defaultDatabaseObjectAppObjectActions['views'],
|
||||||
{
|
{
|
||||||
label: 'Open data',
|
divider: true,
|
||||||
tab: 'ViewDataTab',
|
|
||||||
forceNewTab: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Open structure',
|
|
||||||
tab: 'TableStructureTab',
|
|
||||||
icon: 'img view-structure',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Design query',
|
label: 'Design query',
|
||||||
@@ -197,70 +180,26 @@
|
|||||||
forceNewTab: true,
|
forceNewTab: true,
|
||||||
icon: 'img perspective',
|
icon: 'img perspective',
|
||||||
},
|
},
|
||||||
hasPermission('dbops/model/edit') && {
|
createScriptTemplatesSubmenu('views'),
|
||||||
label: 'Drop view',
|
|
||||||
isDrop: true,
|
|
||||||
requiresWriteAccess: true,
|
|
||||||
},
|
|
||||||
hasPermission('dbops/model/edit') && {
|
|
||||||
label: 'Rename view',
|
|
||||||
isRename: true,
|
|
||||||
requiresWriteAccess: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
divider: true,
|
label: 'SQL generator',
|
||||||
},
|
submenu: [
|
||||||
{
|
{
|
||||||
label: 'Export',
|
label: 'CREATE VIEW',
|
||||||
isExport: true,
|
|
||||||
functionName: 'tableReader',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Open active chart',
|
|
||||||
isActiveChart: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
divider: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: CREATE VIEW',
|
|
||||||
scriptTemplate: 'CREATE OBJECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: ALTER VIEW',
|
|
||||||
scriptTemplate: 'ALTER OBJECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: CREATE TABLE',
|
|
||||||
scriptTemplate: 'CREATE TABLE',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: SELECT',
|
|
||||||
scriptTemplate: 'SELECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: CREATE VIEW',
|
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
createViews: true,
|
createViews: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SQL Generator: DROP VIEW',
|
label: 'DROP VIEW',
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
dropViews: true,
|
dropViews: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
],
|
||||||
case 'matviews':
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
label: 'Open data',
|
|
||||||
tab: 'ViewDataTab',
|
|
||||||
forceNewTab: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Open structure',
|
divider: true,
|
||||||
tab: 'TableStructureTab',
|
|
||||||
},
|
},
|
||||||
hasPermission('dbops/model/edit') && {
|
hasPermission('dbops/model/edit') && {
|
||||||
label: 'Drop view',
|
label: 'Drop view',
|
||||||
@@ -272,10 +211,6 @@
|
|||||||
isRename: true,
|
isRename: true,
|
||||||
requiresWriteAccess: true,
|
requiresWriteAccess: true,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Query designer',
|
|
||||||
isQueryDesigner: true,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
divider: true,
|
divider: true,
|
||||||
},
|
},
|
||||||
@@ -288,37 +223,60 @@
|
|||||||
label: 'Open active chart',
|
label: 'Open active chart',
|
||||||
isActiveChart: true,
|
isActiveChart: true,
|
||||||
},
|
},
|
||||||
|
];
|
||||||
|
case 'matviews':
|
||||||
|
return [
|
||||||
|
...defaultDatabaseObjectAppObjectActions['matviews'],
|
||||||
|
{
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
hasPermission('dbops/model/edit') && {
|
||||||
|
label: 'Drop view',
|
||||||
|
isDrop: true,
|
||||||
|
requiresWriteAccess: true,
|
||||||
|
},
|
||||||
|
hasPermission('dbops/model/edit') && {
|
||||||
|
label: 'Rename view',
|
||||||
|
isRename: true,
|
||||||
|
requiresWriteAccess: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
divider: true,
|
divider: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SQL: CREATE MATERIALIZED VIEW',
|
label: 'Query designer',
|
||||||
scriptTemplate: 'CREATE OBJECT',
|
isQueryDesigner: true,
|
||||||
},
|
},
|
||||||
|
createScriptTemplatesSubmenu('matviews'),
|
||||||
{
|
{
|
||||||
label: 'SQL: ALTER MATERIALIZED VIEW',
|
label: 'SQL generator',
|
||||||
scriptTemplate: 'ALTER OBJECT',
|
submenu: [
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'SQL: CREATE TABLE',
|
label: 'CREATE MATERIALIZED VIEW',
|
||||||
scriptTemplate: 'CREATE TABLE',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: SELECT',
|
|
||||||
scriptTemplate: 'SELECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: CREATE MATERIALIZED VIEW',
|
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
createMatviews: true,
|
createMatviews: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SQL Generator: DROP MATERIALIZED VIEW',
|
label: 'DROP MATERIALIZED VIEW',
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
dropMatviews: true,
|
dropMatviews: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Export',
|
||||||
|
isExport: true,
|
||||||
|
functionName: 'tableReader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open active chart',
|
||||||
|
isActiveChart: true,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
case 'queries':
|
case 'queries':
|
||||||
return [
|
return [
|
||||||
@@ -330,6 +288,10 @@
|
|||||||
];
|
];
|
||||||
case 'procedures':
|
case 'procedures':
|
||||||
return [
|
return [
|
||||||
|
...defaultDatabaseObjectAppObjectActions['procedures'],
|
||||||
|
{
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
hasPermission('dbops/model/edit') && {
|
hasPermission('dbops/model/edit') && {
|
||||||
label: 'Drop procedure',
|
label: 'Drop procedure',
|
||||||
isDrop: true,
|
isDrop: true,
|
||||||
@@ -340,33 +302,31 @@
|
|||||||
isRename: true,
|
isRename: true,
|
||||||
requiresWriteAccess: true,
|
requiresWriteAccess: true,
|
||||||
},
|
},
|
||||||
|
createScriptTemplatesSubmenu('procedures'),
|
||||||
{
|
{
|
||||||
label: 'SQL: CREATE PROCEDURE',
|
label: 'SQL generator',
|
||||||
scriptTemplate: 'CREATE OBJECT',
|
submenu: [
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'SQL: ALTER PROCEDURE',
|
label: 'CREATE PROCEDURE',
|
||||||
scriptTemplate: 'ALTER OBJECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL: EXECUTE',
|
|
||||||
scriptTemplate: 'EXECUTE PROCEDURE',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: CREATE PROCEDURE',
|
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
createProcedures: true,
|
createProcedures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SQL Generator: DROP PROCEDURE',
|
label: 'DROP PROCEDURE',
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
dropProcedures: true,
|
dropProcedures: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
case 'functions':
|
case 'functions':
|
||||||
return [
|
return [
|
||||||
|
...defaultDatabaseObjectAppObjectActions['functions'],
|
||||||
|
{
|
||||||
|
divider: true,
|
||||||
|
},
|
||||||
hasPermission('dbops/model/edit') && {
|
hasPermission('dbops/model/edit') && {
|
||||||
label: 'Drop function',
|
label: 'Drop function',
|
||||||
isDrop: true,
|
isDrop: true,
|
||||||
@@ -377,43 +337,30 @@
|
|||||||
isRename: true,
|
isRename: true,
|
||||||
requiresWriteAccess: true,
|
requiresWriteAccess: true,
|
||||||
},
|
},
|
||||||
|
createScriptTemplatesSubmenu('functions'),
|
||||||
{
|
{
|
||||||
label: 'SQL: CREATE FUNCTION',
|
label: 'SQL generator',
|
||||||
scriptTemplate: 'CREATE OBJECT',
|
submenu: [
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'SQL: ALTER FUNCTION',
|
label: 'CREATE FUNCTION',
|
||||||
scriptTemplate: 'ALTER OBJECT',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'SQL Generator: CREATE FUNCTION',
|
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
createFunctions: true,
|
createFunctions: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'SQL Generator: DROP FUNCTION',
|
label: 'DROP FUNCTION',
|
||||||
sqlGeneratorProps: {
|
sqlGeneratorProps: {
|
||||||
dropFunctions: true,
|
dropFunctions: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
case 'collections':
|
case 'collections':
|
||||||
return [
|
return [
|
||||||
|
...defaultDatabaseObjectAppObjectActions['collections'],
|
||||||
{
|
{
|
||||||
label: 'Open data',
|
divider: true,
|
||||||
tab: 'CollectionDataTab',
|
|
||||||
forceNewTab: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Open JSON',
|
|
||||||
tab: 'CollectionDataTab',
|
|
||||||
forceNewTab: true,
|
|
||||||
initialData: {
|
|
||||||
grid: {
|
|
||||||
isJsonView: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Design perspective query',
|
label: 'Design perspective query',
|
||||||
@@ -659,15 +606,30 @@
|
|||||||
// fixedTargetPureName: data.pureName,
|
// fixedTargetPureName: data.pureName,
|
||||||
// },
|
// },
|
||||||
// });
|
// });
|
||||||
|
// } else if (menu.isShowSql) {
|
||||||
|
// openNewTab({
|
||||||
|
// title: data.pureName,
|
||||||
|
// icon: 'img sql-file',
|
||||||
|
// tabComponent: 'SqlObjectTab',
|
||||||
|
// tabPreviewMode: true,
|
||||||
|
// props: {
|
||||||
|
// conid: data.conid,
|
||||||
|
// database: data.database,
|
||||||
|
// schemaName: data.schemaName,
|
||||||
|
// pureName: data.pureName,
|
||||||
|
// objectTypeField: data.objectTypeField,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
} else {
|
} else {
|
||||||
openDatabaseObjectDetail(
|
openDatabaseObjectDetail(
|
||||||
menu.tab,
|
menu.tab,
|
||||||
menu.scriptTemplate,
|
menu.scriptTemplate,
|
||||||
data,
|
{ ...data, defaultActionId: menu.defaultActionId },
|
||||||
menu.forceNewTab,
|
menu.forceNewTab,
|
||||||
menu.initialData,
|
menu.initialData,
|
||||||
menu.icon,
|
menu.icon,
|
||||||
data
|
data,
|
||||||
|
!!menu.defaultActionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -697,11 +659,12 @@
|
|||||||
export async function openDatabaseObjectDetail(
|
export async function openDatabaseObjectDetail(
|
||||||
tabComponent,
|
tabComponent,
|
||||||
scriptTemplate,
|
scriptTemplate,
|
||||||
{ schemaName, pureName, conid, database, objectTypeField },
|
{ schemaName, pureName, conid, database, objectTypeField, defaultActionId },
|
||||||
forceNewTab?,
|
forceNewTab?,
|
||||||
initialData?,
|
initialData?,
|
||||||
icon?,
|
icon?,
|
||||||
appObjectData?
|
appObjectData?,
|
||||||
|
tabPreviewMode?
|
||||||
) {
|
) {
|
||||||
const connection = await getConnectionInfo({ conid });
|
const connection = await getConnectionInfo({ conid });
|
||||||
const tooltip = `${getConnectionLabel(connection)}\n${database}\n${fullDisplayName({
|
const tooltip = `${getConnectionLabel(connection)}\n${database}\n${fullDisplayName({
|
||||||
@@ -711,12 +674,16 @@
|
|||||||
|
|
||||||
openNewTab(
|
openNewTab(
|
||||||
{
|
{
|
||||||
title: scriptTemplate ? 'Query #' : getObjectTitle(connection, schemaName, pureName),
|
// title: getObjectTitle(connection, schemaName, pureName),
|
||||||
|
title: tabComponent ? getObjectTitle(connection, schemaName, pureName) : 'Query #',
|
||||||
tooltip,
|
tooltip,
|
||||||
icon: icon || (scriptTemplate ? 'img sql-file' : databaseObjectIcons[objectTypeField]),
|
icon:
|
||||||
tabComponent: scriptTemplate ? 'QueryTab' : tabComponent,
|
icon ||
|
||||||
|
(scriptTemplate || tabComponent == 'SqlObjectTab' ? 'img sql-file' : databaseObjectIcons[objectTypeField]),
|
||||||
|
tabComponent: tabComponent ?? 'QueryTab',
|
||||||
appObject: 'DatabaseObjectAppObject',
|
appObject: 'DatabaseObjectAppObject',
|
||||||
appObjectData,
|
appObjectData,
|
||||||
|
tabPreviewMode,
|
||||||
props: {
|
props: {
|
||||||
schemaName,
|
schemaName,
|
||||||
pureName,
|
pureName,
|
||||||
@@ -724,6 +691,7 @@
|
|||||||
database,
|
database,
|
||||||
objectTypeField,
|
objectTypeField,
|
||||||
initialArgs: scriptTemplate ? { scriptTemplate } : null,
|
initialArgs: scriptTemplate ? { scriptTemplate } : null,
|
||||||
|
defaultActionId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
initialData,
|
initialData,
|
||||||
@@ -731,31 +699,62 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleDatabaseObjectClick(data, forceNewTab = false) {
|
export function handleDatabaseObjectClick(
|
||||||
|
data,
|
||||||
|
{ forceNewTab = false, tabPreviewMode = false, focusTab = false } = {}
|
||||||
|
) {
|
||||||
const { schemaName, pureName, conid, database, objectTypeField } = data;
|
const { schemaName, pureName, conid, database, objectTypeField } = data;
|
||||||
const driver = findEngineDriver(data, getExtensions());
|
const driver = findEngineDriver(data, getExtensions());
|
||||||
|
|
||||||
const configuredAction = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`];
|
const activeTab = getActiveTab();
|
||||||
const overrideMenu = createMenus(objectTypeField, driver).find(x => x.label && x.label == configuredAction);
|
const activeTabProps = activeTab?.props || {};
|
||||||
if (overrideMenu) {
|
const activeDefaultActionId = activeTab?.props?.defaultActionId;
|
||||||
databaseObjectMenuClickHandler(data, overrideMenu);
|
|
||||||
|
if (matchDatabaseObjectAppObject(data, activeTabProps)) {
|
||||||
|
if (!tabPreviewMode) {
|
||||||
|
openedTabs.update(tabs => {
|
||||||
|
return tabs.map(tab => ({
|
||||||
|
...tab,
|
||||||
|
tabPreviewMode: tab.tabid == activeTab.tabid ? false : tab.tabPreviewMode,
|
||||||
|
focused: focusTab && tab.tabid == activeTab.tabid ? true : tab.focused,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const availableDefaultActions = defaultDatabaseObjectAppObjectActions[objectTypeField];
|
||||||
|
|
||||||
|
const configuredActionId = getCurrentSettings()[`defaultAction.dbObjectClick.${objectTypeField}`];
|
||||||
|
const prefferedAction =
|
||||||
|
availableDefaultActions.find(x => x.defaultActionId == activeDefaultActionId) ??
|
||||||
|
availableDefaultActions.find(x => x.defaultActionId == configuredActionId) ??
|
||||||
|
availableDefaultActions[0];
|
||||||
|
|
||||||
|
// console.log('activeTab', activeTab);
|
||||||
|
|
||||||
|
// const overrideMenu = createMenus(objectTypeField, driver).find(x => x.label && x.label == configuredAction);
|
||||||
|
// if (overrideMenu) {
|
||||||
|
// databaseObjectMenuClickHandler(data, overrideMenu);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
openDatabaseObjectDetail(
|
openDatabaseObjectDetail(
|
||||||
defaultTabs[objectTypeField],
|
prefferedAction.tab,
|
||||||
defaultTabs[objectTypeField] ? null : 'CREATE OBJECT',
|
activeTabProps?.scriptTemplate,
|
||||||
{
|
{
|
||||||
schemaName,
|
schemaName,
|
||||||
pureName,
|
pureName,
|
||||||
conid,
|
conid,
|
||||||
database,
|
database,
|
||||||
objectTypeField,
|
objectTypeField,
|
||||||
|
defaultActionId: prefferedAction.defaultActionId,
|
||||||
},
|
},
|
||||||
forceNewTab,
|
forceNewTab,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
data
|
data,
|
||||||
|
tabPreviewMode
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -769,13 +768,7 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDatabaseObjectMenu(data, connection = null) {
|
function menuItemMapper(menu, data, connection) {
|
||||||
const driver = findEngineDriver(data, getExtensions());
|
|
||||||
|
|
||||||
const { objectTypeField } = data;
|
|
||||||
return createMenus(objectTypeField, driver)
|
|
||||||
.filter(x => x)
|
|
||||||
.map(menu => {
|
|
||||||
if (menu.divider) return menu;
|
if (menu.divider) return menu;
|
||||||
|
|
||||||
if (menu.isExport) {
|
if (menu.isExport) {
|
||||||
@@ -820,13 +813,29 @@
|
|||||||
if (connection?.isReadOnly && menu.requiresWriteAccess) {
|
if (connection?.isReadOnly && menu.requiresWriteAccess) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (menu.submenu) {
|
||||||
|
return {
|
||||||
|
...menu,
|
||||||
|
submenu: menu.submenu.map(x => menuItemMapper(x, data, connection)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
text: menu.label,
|
text: menu.label,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
databaseObjectMenuClickHandler(data, menu);
|
databaseObjectMenuClickHandler(data, menu);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export function createDatabaseObjectMenu(data, connection = null) {
|
||||||
|
const driver = findEngineDriver(data, getExtensions());
|
||||||
|
|
||||||
|
const { objectTypeField } = data;
|
||||||
|
return createMenus(objectTypeField, driver)
|
||||||
|
.filter(x => x)
|
||||||
|
.map(menu => menuItemMapper(menu, data, connection));
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatRowCount(value) {
|
function formatRowCount(value) {
|
||||||
@@ -838,6 +847,10 @@
|
|||||||
export function createAppObjectMenu(data) {
|
export function createAppObjectMenu(data) {
|
||||||
return createDatabaseObjectMenu(data);
|
return createDatabaseObjectMenu(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function handleObjectClick(data, { forceNewTab = false, tabPreviewMode = false, focusTab = false }) {
|
||||||
|
return handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode, focusTab });
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@@ -846,10 +859,13 @@
|
|||||||
import {
|
import {
|
||||||
currentDatabase,
|
currentDatabase,
|
||||||
extensions,
|
extensions,
|
||||||
|
getActiveTab,
|
||||||
getCurrentSettings,
|
getCurrentSettings,
|
||||||
getExtensions,
|
getExtensions,
|
||||||
openedConnections,
|
openedConnections,
|
||||||
|
openedTabs,
|
||||||
pinnedTables,
|
pinnedTables,
|
||||||
|
selectedDatabaseObjectAppObject,
|
||||||
} from '../stores';
|
} from '../stores';
|
||||||
import openNewTab from '../utility/openNewTab';
|
import openNewTab from '../utility/openNewTab';
|
||||||
import {
|
import {
|
||||||
@@ -877,12 +893,15 @@
|
|||||||
import { getDefaultFileFormat } from '../plugins/fileformats';
|
import { getDefaultFileFormat } from '../plugins/fileformats';
|
||||||
import hasPermission from '../utility/hasPermission';
|
import hasPermission from '../utility/hasPermission';
|
||||||
import { openImportExportTab } from '../utility/importExportTools';
|
import { openImportExportTab } from '../utility/importExportTools';
|
||||||
|
import { defaultDatabaseObjectAppObjectActions, matchDatabaseObjectAppObject } from './appObjectTools';
|
||||||
|
import { getSupportedScriptTemplates } from '../utility/applyScriptTemplate';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let passProps;
|
export let passProps;
|
||||||
|
|
||||||
function handleClick(forceNewTab = false) {
|
function handleClick({ forceNewTab = false, tabPreviewMode = false, focusTab = false } = {}) {
|
||||||
handleDatabaseObjectClick(data, forceNewTab);
|
$selectedDatabaseObjectAppObject = _.pick(data, ['conid', 'database', 'objectTypeField', 'pureName', 'schemaName']);
|
||||||
|
handleDatabaseObjectClick(data, { forceNewTab, tabPreviewMode, focusTab });
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMenu() {
|
function createMenu() {
|
||||||
@@ -915,8 +934,10 @@
|
|||||||
onPin={isPinned ? null : () => pinnedTables.update(list => [...list, data])}
|
onPin={isPinned ? null : () => pinnedTables.update(list => [...list, data])}
|
||||||
onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null}
|
onUnpin={isPinned ? () => pinnedTables.update(list => list.filter(x => !testEqual(x, data))) : null}
|
||||||
extInfo={getExtInfo(data)}
|
extInfo={getExtInfo(data)}
|
||||||
on:click={() => handleClick()}
|
isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)}
|
||||||
on:middleclick={() => handleClick(true)}
|
on:click={() => handleClick({ tabPreviewMode: true })}
|
||||||
|
on:middleclick={() => handleClick({ forceNewTab: true })}
|
||||||
|
on:dblclick={() => handleClick({ tabPreviewMode: false, focusTab: true })}
|
||||||
on:expand
|
on:expand
|
||||||
on:dragstart
|
on:dragstart
|
||||||
on:dragenter
|
on:dragenter
|
||||||
|
|||||||
80
packages/web/src/appobj/appObjectTools.ts
Normal file
80
packages/web/src/appobj/appObjectTools.ts
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
export function matchDatabaseObjectAppObject(obj1, obj2) {
|
||||||
|
return (
|
||||||
|
obj1?.objectTypeField == obj2?.objectTypeField &&
|
||||||
|
obj1?.conid == obj2?.conid &&
|
||||||
|
obj1?.database == obj2?.database &&
|
||||||
|
obj1?.pureName == obj2?.pureName &&
|
||||||
|
obj1?.schemaName == obj2?.schemaName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTableLikeActions(dataTab) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'Open data',
|
||||||
|
tab: dataTab,
|
||||||
|
defaultActionId: 'openTable',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open form',
|
||||||
|
tab: dataTab,
|
||||||
|
initialData: {
|
||||||
|
grid: {
|
||||||
|
isFormView: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultActionId: 'openForm',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open structure',
|
||||||
|
tab: 'TableStructureTab',
|
||||||
|
icon: 'img table-structure',
|
||||||
|
defaultActionId: 'openStructure',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Show SQL',
|
||||||
|
tab: 'SqlObjectTab',
|
||||||
|
defaultActionId: 'showSql',
|
||||||
|
icon: 'img sql-file',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultDatabaseObjectAppObjectActions = {
|
||||||
|
tables: getTableLikeActions('TableDataTab'),
|
||||||
|
views: getTableLikeActions('ViewDataTab'),
|
||||||
|
matviews: getTableLikeActions('ViewDataTab'),
|
||||||
|
procedures: [
|
||||||
|
{
|
||||||
|
label: 'Show SQL',
|
||||||
|
tab: 'SqlObjectTab',
|
||||||
|
defaultActionId: 'showSql',
|
||||||
|
icon: 'img sql-file',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
functions: [
|
||||||
|
{
|
||||||
|
label: 'Show SQL',
|
||||||
|
tab: 'SqlObjectTab',
|
||||||
|
defaultActionId: 'showSql',
|
||||||
|
icon: 'img sql-file',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
collections: [
|
||||||
|
{
|
||||||
|
label: 'Open data',
|
||||||
|
tab: 'CollectionDataTab',
|
||||||
|
defaultActionId: 'openTable',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Open JSON',
|
||||||
|
tab: 'CollectionDataTab',
|
||||||
|
defaultActionId: 'openJson',
|
||||||
|
initialData: {
|
||||||
|
grid: {
|
||||||
|
isJsonView: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
@@ -142,6 +142,8 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isColumnManagerFocused = false;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if allowChangeChangeSetStructure}
|
{#if allowChangeChangeSetStructure}
|
||||||
@@ -207,9 +209,13 @@
|
|||||||
bind:this={domFocusField}
|
bind:this={domFocusField}
|
||||||
on:keydown={handleKeyDown}
|
on:keydown={handleKeyDown}
|
||||||
on:focus={() => {
|
on:focus={() => {
|
||||||
|
isColumnManagerFocused = true;
|
||||||
// activator.activate();
|
// activator.activate();
|
||||||
// invalidateCommands();
|
// invalidateCommands();
|
||||||
}}
|
}}
|
||||||
|
on:blur={() => {
|
||||||
|
isColumnManagerFocused = false;
|
||||||
|
}}
|
||||||
on:copy={copyToClipboard}
|
on:copy={copyToClipboard}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -224,6 +230,7 @@
|
|||||||
{database}
|
{database}
|
||||||
{tableInfo}
|
{tableInfo}
|
||||||
{setTableInfo}
|
{setTableInfo}
|
||||||
|
{isColumnManagerFocused}
|
||||||
columnInfo={tableInfo?.columns?.[columnIndex]}
|
columnInfo={tableInfo?.columns?.[columnIndex]}
|
||||||
{columnIndex}
|
{columnIndex}
|
||||||
{allowChangeChangeSetStructure}
|
{allowChangeChangeSetStructure}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
export let columnInfo = null;
|
export let columnInfo = null;
|
||||||
export let columnIndex = -1;
|
export let columnIndex = -1;
|
||||||
|
|
||||||
|
export let isColumnManagerFocused = false;
|
||||||
|
|
||||||
export let allowChangeChangeSetStructure = false;
|
export let allowChangeChangeSetStructure = false;
|
||||||
$: addDataCommand = allowChangeChangeSetStructure;
|
$: addDataCommand = allowChangeChangeSetStructure;
|
||||||
|
|
||||||
@@ -49,6 +51,7 @@
|
|||||||
else display.focusColumns([column.uniqueName]);
|
else display.focusColumns([column.uniqueName]);
|
||||||
}}
|
}}
|
||||||
class:isSelected
|
class:isSelected
|
||||||
|
class:isFocused={isColumnManagerFocused}
|
||||||
on:click
|
on:click
|
||||||
on:mousedown
|
on:mousedown
|
||||||
on:mousemove
|
on:mousemove
|
||||||
@@ -123,6 +126,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.row.isSelected {
|
.row.isSelected {
|
||||||
|
background: var(--theme-bg-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.row.isSelected.isFocused {
|
||||||
background: var(--theme-bg-selected);
|
background: var(--theme-bg-selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,6 +173,9 @@
|
|||||||
background: var(--theme-bg-volcano);
|
background: var(--theme-bg-volcano);
|
||||||
}
|
}
|
||||||
td.isSelected {
|
td.isSelected {
|
||||||
|
background: var(--theme-bg-3);
|
||||||
|
}
|
||||||
|
:global(.data-grid-focused) td.isSelected {
|
||||||
background: var(--theme-bg-selected);
|
background: var(--theme-bg-selected);
|
||||||
}
|
}
|
||||||
td.isDeleted {
|
td.isDeleted {
|
||||||
|
|||||||
@@ -472,7 +472,7 @@
|
|||||||
export let dataEditorTypesBehaviourOverride = null;
|
export let dataEditorTypesBehaviourOverride = null;
|
||||||
|
|
||||||
const wheelRowCount = 5;
|
const wheelRowCount = 5;
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
let containerHeight = 0;
|
let containerHeight = 0;
|
||||||
let containerWidth = 0;
|
let containerWidth = 0;
|
||||||
@@ -492,6 +492,8 @@
|
|||||||
let autofillSelectedCells = emptyCellArray;
|
let autofillSelectedCells = emptyCellArray;
|
||||||
const domFilterControlsRef = createRef({});
|
const domFilterControlsRef = createRef({});
|
||||||
|
|
||||||
|
let isGridFocused=false;
|
||||||
|
|
||||||
const tabid = getContext('tabid');
|
const tabid = getContext('tabid');
|
||||||
|
|
||||||
let unsubscribeDbRefresh;
|
let unsubscribeDbRefresh;
|
||||||
@@ -1041,7 +1043,6 @@
|
|||||||
return !hideGridLeftColumn;
|
return !hideGridLeftColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
$: autofillMarkerCell =
|
$: autofillMarkerCell =
|
||||||
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
selectedCells && selectedCells.length > 0 && _.uniq(selectedCells.map(x => x[0])).length == 1
|
||||||
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
? [_.max(selectedCells.map(x => x[0])), _.max(selectedCells.map(x => x[1]))]
|
||||||
@@ -1134,7 +1135,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if ($tabVisible && domFocusField && focusOnVisible) {
|
$: if ($tabFocused && domFocusField && focusOnVisible) {
|
||||||
domFocusField.focus();
|
domFocusField.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1863,6 +1864,7 @@
|
|||||||
{:else}
|
{:else}
|
||||||
<div
|
<div
|
||||||
class="container"
|
class="container"
|
||||||
|
class:data-grid-focused={isGridFocused}
|
||||||
bind:clientWidth={containerWidth}
|
bind:clientWidth={containerWidth}
|
||||||
bind:clientHeight={containerHeight}
|
bind:clientHeight={containerHeight}
|
||||||
use:contextMenu={buildMenu}
|
use:contextMenu={buildMenu}
|
||||||
@@ -1877,10 +1879,14 @@
|
|||||||
on:focus={() => {
|
on:focus={() => {
|
||||||
activator.activate();
|
activator.activate();
|
||||||
invalidateCommands();
|
invalidateCommands();
|
||||||
|
isGridFocused = true;
|
||||||
}}
|
}}
|
||||||
|
on:blur
|
||||||
on:paste={handlePaste}
|
on:paste={handlePaste}
|
||||||
on:copy={copyToClipboard}
|
on:copy={copyToClipboard}
|
||||||
on:blur={handleBlur}
|
on:blur={() => {
|
||||||
|
isGridFocused = false;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<table
|
<table
|
||||||
class="table"
|
class="table"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
$: searchValue = value || '';
|
$: searchValue = value || '';
|
||||||
export let isDebounced = false;
|
export let isDebounced = false;
|
||||||
|
export let onFocusFilteredList = null;
|
||||||
|
|
||||||
let domInput;
|
let domInput;
|
||||||
|
|
||||||
@@ -14,9 +15,17 @@
|
|||||||
if (e.keyCode == keycodes.escape) {
|
if (e.keyCode == keycodes.escape) {
|
||||||
value = '';
|
value = '';
|
||||||
}
|
}
|
||||||
|
if (e.keyCode == keycodes.downArrow || e.keyCode == keycodes.pageDown || e.keyCode == keycodes.enter) {
|
||||||
|
onFocusFilteredList?.();
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const debouncedSet = _.debounce(x => (value = x), 500);
|
const debouncedSet = _.debounce(x => (value = x), 500);
|
||||||
|
|
||||||
|
export function focus() {
|
||||||
|
domInput.focus();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -217,12 +217,12 @@
|
|||||||
$: rowHeight = $dataGridRowHeight;
|
$: rowHeight = $dataGridRowHeight;
|
||||||
let currentCell = [0, 0];
|
let currentCell = [0, 0];
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
const domCells = {};
|
const domCells = {};
|
||||||
|
|
||||||
let domFocusField;
|
let domFocusField;
|
||||||
|
|
||||||
$: if ($tabVisible && domFocusField && focusOnVisible) {
|
$: if ($tabFocused && domFocusField && focusOnVisible) {
|
||||||
domFocusField.focus();
|
domFocusField.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,8 @@
|
|||||||
|
|
||||||
--theme-border: #555;
|
--theme-border: #555;
|
||||||
|
|
||||||
--theme-bg-hover: #112a45;
|
--theme-bg-hover: #555;
|
||||||
--theme-bg-selected: #15395b; /* blue-3 */
|
--theme-bg-selected: #1d4d7e; /* blue-4 */
|
||||||
--theme-bg-selected-point: #1765ad; /* blue-5 */
|
--theme-bg-selected-point: #1765ad; /* blue-5 */
|
||||||
|
|
||||||
--theme-bg-statusbar-inv: #0050b3;
|
--theme-bg-statusbar-inv: #0050b3;
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
--theme-border: #ccc;
|
--theme-border: #ccc;
|
||||||
|
|
||||||
--theme-bg-hover: #bae7ff;
|
--theme-bg-hover: #ccc;
|
||||||
--theme-bg-selected: #91d5ff; /* blue-3 */
|
--theme-bg-selected: #91d5ff; /* blue-3 */
|
||||||
--theme-bg-selected-point: #40a9ff; /* blue-5 */
|
--theme-bg-selected-point: #40a9ff; /* blue-5 */
|
||||||
|
|
||||||
|
|||||||
18
packages/web/src/settings/FormDefaultActionField.svelte
Normal file
18
packages/web/src/settings/FormDefaultActionField.svelte
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<script alng="ts">
|
||||||
|
import { defaultDatabaseObjectAppObjectActions } from '../appobj/appObjectTools';
|
||||||
|
import FormSelectField from '../forms/FormSelectField.svelte';
|
||||||
|
|
||||||
|
export let label;
|
||||||
|
export let objectTypeField;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<FormSelectField
|
||||||
|
{label}
|
||||||
|
name={`defaultAction.dbObjectClick.${objectTypeField}`}
|
||||||
|
isNative
|
||||||
|
defaultValue={defaultDatabaseObjectAppObjectActions[objectTypeField][0]?.defaultActionId}
|
||||||
|
options={defaultDatabaseObjectAppObjectActions[objectTypeField].map(x => ({
|
||||||
|
value: x.defaultActionId,
|
||||||
|
label: x.label,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
import { useSettings } from '../utility/metadataLoaders';
|
import { useSettings } from '../utility/metadataLoaders';
|
||||||
import { derived } from 'svelte/store';
|
import { derived } from 'svelte/store';
|
||||||
import { safeFormatDate } from 'dbgate-tools';
|
import { safeFormatDate } from 'dbgate-tools';
|
||||||
|
import FormDefaultActionField from './FormDefaultActionField.svelte';
|
||||||
|
|
||||||
const electron = getElectron();
|
const electron = getElectron();
|
||||||
let restartWarning = false;
|
let restartWarning = false;
|
||||||
@@ -288,56 +289,11 @@ ORDER BY
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormSelectField
|
<FormDefaultActionField label="Table click" objectTypeField="tables" />
|
||||||
label="Table click"
|
<FormDefaultActionField label="View click" objectTypeField="views" />
|
||||||
name="defaultAction.dbObjectClick.tables"
|
<FormDefaultActionField label="Materialized view click" objectTypeField="matviews" />
|
||||||
isNative
|
<FormDefaultActionField label="Procedure click" objectTypeField="procedures" />
|
||||||
defaultValue=""
|
<FormDefaultActionField label="Function click" objectTypeField="functions" />
|
||||||
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>
|
</svelte:fragment>
|
||||||
<svelte:fragment slot="5">
|
<svelte:fragment slot="5">
|
||||||
<div class="heading">Confirmations</div>
|
<div class="heading">Confirmations</div>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ export interface TabDefinition {
|
|||||||
tabOrder?: number;
|
tabOrder?: number;
|
||||||
multiTabIndex?: number;
|
multiTabIndex?: number;
|
||||||
unsaved?: boolean;
|
unsaved?: boolean;
|
||||||
|
tabPreviewMode?: boolean;
|
||||||
|
focused?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function writableWithStorage<T>(defaultValue: T, storageName) {
|
export function writableWithStorage<T>(defaultValue: T, storageName) {
|
||||||
@@ -91,7 +93,7 @@ export const openedConnections = writable([]);
|
|||||||
export const temporaryOpenedConnections = writable([]);
|
export const temporaryOpenedConnections = writable([]);
|
||||||
export const openedSingleDatabaseConnections = writable([]);
|
export const openedSingleDatabaseConnections = writable([]);
|
||||||
export const expandedConnections = writable([]);
|
export const expandedConnections = writable([]);
|
||||||
export const currentDatabase = writable(null);
|
export const currentDatabase = writableWithForage(null, 'currentDatabase');
|
||||||
export const openedTabs = writableWithForage<TabDefinition[]>([], getOpenedTabsStorageName(), x => [...(x || [])]);
|
export const openedTabs = writableWithForage<TabDefinition[]>([], getOpenedTabsStorageName(), x => [...(x || [])]);
|
||||||
export const copyRowsFormat = writableWithStorage('textWithoutHeaders', 'copyRowsFormat');
|
export const copyRowsFormat = writableWithStorage('textWithoutHeaders', 'copyRowsFormat');
|
||||||
export const extensions = writable<ExtensionsDirectory>(null);
|
export const extensions = writable<ExtensionsDirectory>(null);
|
||||||
@@ -155,6 +157,8 @@ export const activeDbKeysStore = writableWithStorage({}, 'activeDbKeysStore');
|
|||||||
export const appliedCurrentSchema = writable<string>(null);
|
export const appliedCurrentSchema = writable<string>(null);
|
||||||
export const loadingSchemaLists = writable({}); // dict [`${conid}::${database}`]: true
|
export const loadingSchemaLists = writable({}); // dict [`${conid}::${database}`]: true
|
||||||
|
|
||||||
|
export const selectedDatabaseObjectAppObject = writable(null);
|
||||||
|
|
||||||
export const currentThemeDefinition = derived([currentTheme, extensions], ([$currentTheme, $extensions]) =>
|
export const currentThemeDefinition = derived([currentTheme, extensions], ([$currentTheme, $extensions]) =>
|
||||||
$extensions.themes.find(x => x.themeClassName == $currentTheme)
|
$extensions.themes.find(x => x.themeClassName == $currentTheme)
|
||||||
);
|
);
|
||||||
@@ -324,6 +328,12 @@ appliedCurrentSchema.subscribe(value => {
|
|||||||
});
|
});
|
||||||
export const getAppliedCurrentSchema = () => appliedCurrentSchemaValue;
|
export const getAppliedCurrentSchema = () => appliedCurrentSchemaValue;
|
||||||
|
|
||||||
|
let selectedDatabaseObjectAppObjectValue = null;
|
||||||
|
selectedDatabaseObjectAppObject.subscribe(value => {
|
||||||
|
selectedDatabaseObjectAppObjectValue = value;
|
||||||
|
});
|
||||||
|
export const getSelectedDatabaseObjectAppObject = () => selectedDatabaseObjectAppObjectValue;
|
||||||
|
|
||||||
let openedModalsValue = [];
|
let openedModalsValue = [];
|
||||||
openedModals.subscribe(value => {
|
openedModals.subscribe(value => {
|
||||||
openedModalsValue = value;
|
openedModalsValue = value;
|
||||||
|
|||||||
@@ -4,17 +4,22 @@
|
|||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
export let tabVisible;
|
export let tabVisible;
|
||||||
|
export let tabFocused;
|
||||||
export let tabComponent;
|
export let tabComponent;
|
||||||
|
|
||||||
const tabVisibleStore = writable(tabVisible);
|
|
||||||
setContext('tabid', tabid);
|
setContext('tabid', tabid);
|
||||||
setContext('tabVisible', tabVisibleStore);
|
|
||||||
|
|
||||||
|
const tabVisibleStore = writable(tabVisible);
|
||||||
|
setContext('tabVisible', tabVisibleStore);
|
||||||
$: tabVisibleStore.set(tabVisible);
|
$: tabVisibleStore.set(tabVisible);
|
||||||
|
|
||||||
|
const tabFocusedStore = writable(tabFocused);
|
||||||
|
setContext('tabFocused', tabFocusedStore);
|
||||||
|
$: tabFocusedStore.set(tabFocused);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class:tabVisible>
|
<div class:tabVisible>
|
||||||
<svelte:component this={tabComponent} {...$$restProps} {tabid} {tabVisible} />
|
<svelte:component this={tabComponent} {...$$restProps} {tabid} {tabVisible} {tabFocused} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
@@ -52,5 +52,6 @@
|
|||||||
{tabid}
|
{tabid}
|
||||||
unsaved={openedTabsByTabId[tabid]?.unsaved}
|
unsaved={openedTabsByTabId[tabid]?.unsaved}
|
||||||
tabVisible={tabid == shownTab?.tabid}
|
tabVisible={tabid == shownTab?.tabid}
|
||||||
|
tabFocused={tabid == shownTab?.tabid && shownTab?.focused}
|
||||||
/>
|
/>
|
||||||
{/each}
|
{/each}
|
||||||
|
|||||||
@@ -241,7 +241,7 @@
|
|||||||
const hasAnyOtherTab = getOpenedTabs().filter(x => !x.closedTime).length >= 1;
|
const hasAnyOtherTab = getOpenedTabs().filter(x => !x.closedTime).length >= 1;
|
||||||
const hasAnyModalOpen = getOpenedModals().length > 0;
|
const hasAnyModalOpen = getOpenedModals().length > 0;
|
||||||
|
|
||||||
return hasAnyOtherTab && !hasConfirmModalOpen;
|
return hasAnyOtherTab && !hasAnyModalOpen;
|
||||||
},
|
},
|
||||||
onClick: closeCurrentTab,
|
onClick: closeCurrentTab,
|
||||||
});
|
});
|
||||||
@@ -323,6 +323,7 @@
|
|||||||
import CloseTabModal from '../modals/CloseTabModal.svelte';
|
import CloseTabModal from '../modals/CloseTabModal.svelte';
|
||||||
import SwitchDatabaseModal from '../modals/SwitchDatabaseModal.svelte';
|
import SwitchDatabaseModal from '../modals/SwitchDatabaseModal.svelte';
|
||||||
import { getConnectionLabel } from 'dbgate-tools';
|
import { getConnectionLabel } from 'dbgate-tools';
|
||||||
|
import { handleAfterTabClick } from '../utility/changeCurrentDbByTab';
|
||||||
|
|
||||||
export let multiTabIndex;
|
export let multiTabIndex;
|
||||||
export let shownTab;
|
export let shownTab;
|
||||||
@@ -362,6 +363,7 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setSelectedTab(tabid);
|
setSelectedTab(tabid);
|
||||||
|
handleAfterTabClick();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMouseDown = (e, tabid) => {
|
const handleMouseDown = (e, tabid) => {
|
||||||
@@ -377,6 +379,17 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDoubleClick = (e, tabid) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
openedTabs.update(tabs =>
|
||||||
|
tabs.map(x => ({
|
||||||
|
...x,
|
||||||
|
tabPreviewMode: x.tabid == tabid ? false : x.tabPreviewMode,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const getContextMenu = tab => () => {
|
const getContextMenu = tab => () => {
|
||||||
const { tabid, props, tabComponent, appObject, appObjectData } = tab;
|
const { tabid, props, tabComponent, appObject, appObjectData } = tab;
|
||||||
|
|
||||||
@@ -596,9 +609,11 @@
|
|||||||
class:selected={$draggingTab || $draggingDbGroup
|
class:selected={$draggingTab || $draggingDbGroup
|
||||||
? tab.tabid == $draggingTabTarget?.tabid
|
? tab.tabid == $draggingTabTarget?.tabid
|
||||||
: tab.tabid == shownTab?.tabid}
|
: tab.tabid == shownTab?.tabid}
|
||||||
|
class:preview={!!tab.tabPreviewMode}
|
||||||
on:click={e => handleTabClick(e, tab.tabid)}
|
on:click={e => handleTabClick(e, tab.tabid)}
|
||||||
on:mousedown={e => handleMouseDown(e, tab.tabid)}
|
on:mousedown={e => handleMouseDown(e, tab.tabid)}
|
||||||
on:mouseup={e => handleMouseUp(e, tab.tabid)}
|
on:mouseup={e => handleMouseUp(e, tab.tabid)}
|
||||||
|
on:dblclick={e => handleDoubleClick(e, tab.tabid)}
|
||||||
use:contextMenu={getContextMenu(tab)}
|
use:contextMenu={getContextMenu(tab)}
|
||||||
draggable={true}
|
draggable={true}
|
||||||
on:dragstart={async e => {
|
on:dragstart={async e => {
|
||||||
@@ -742,6 +757,9 @@
|
|||||||
.file-tab-item.selected {
|
.file-tab-item.selected {
|
||||||
background-color: var(--theme-bg-0);
|
background-color: var(--theme-bg-0);
|
||||||
}
|
}
|
||||||
|
.file-tab-item.preview {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
.file-name {
|
.file-name {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
|||||||
@@ -47,13 +47,13 @@
|
|||||||
export let tabid;
|
export let tabid;
|
||||||
export let savedFile;
|
export let savedFile;
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
export const activator = createActivator('FavoriteEditorTab', false);
|
export const activator = createActivator('FavoriteEditorTab', false);
|
||||||
|
|
||||||
let domEditor;
|
let domEditor;
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,14 +27,14 @@
|
|||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
export const activator = createActivator('JsonEditorTab', false);
|
export const activator = createActivator('JsonEditorTab', false);
|
||||||
|
|
||||||
let domEditor;
|
let domEditor;
|
||||||
let domToolStrip;
|
let domToolStrip;
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,14 +81,14 @@
|
|||||||
|
|
||||||
let jslid = null;
|
let jslid = null;
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
export const activator = createActivator('JsonLinesEditorTab', false);
|
export const activator = createActivator('JsonLinesEditorTab', false);
|
||||||
|
|
||||||
let domEditor;
|
let domEditor;
|
||||||
let domToolStrip;
|
let domToolStrip;
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,13 +41,13 @@
|
|||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
export const activator = createActivator('MarkdownEditorTab', false);
|
export const activator = createActivator('MarkdownEditorTab', false);
|
||||||
|
|
||||||
let domEditor;
|
let domEditor;
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,7 @@
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
const timerLabel = useTimerLabel();
|
const timerLabel = useTimerLabel();
|
||||||
|
|
||||||
let busy = false;
|
let busy = false;
|
||||||
@@ -182,7 +182,7 @@
|
|||||||
invalidateCommands();
|
invalidateCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,7 +454,7 @@
|
|||||||
/>
|
/>
|
||||||
{:else}
|
{:else}
|
||||||
<AceEditor
|
<AceEditor
|
||||||
mode={driver?.editorMode || 'text'}
|
mode={driver?.editorMode || 'sql'}
|
||||||
value={$editorState.value || ''}
|
value={$editorState.value || ''}
|
||||||
splitterOptions={driver?.getQuerySplitterOptions('editor')}
|
splitterOptions={driver?.getQuerySplitterOptions('editor')}
|
||||||
options={{
|
options={{
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
const timerLabel = useTimerLabel();
|
const timerLabel = useTimerLabel();
|
||||||
|
|
||||||
let runnerId;
|
let runnerId;
|
||||||
@@ -82,7 +82,7 @@
|
|||||||
invalidateCommands();
|
invalidateCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
113
packages/web/src/tabs/SqlObjectTab.svelte
Normal file
113
packages/web/src/tabs/SqlObjectTab.svelte
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
<script lang="ts" context="module">
|
||||||
|
const getCurrentEditor = () => getActiveComponent('SqlObjectTab');
|
||||||
|
|
||||||
|
registerCommand({
|
||||||
|
id: 'sqlObject.find',
|
||||||
|
category: 'SQL Object',
|
||||||
|
name: 'Find',
|
||||||
|
keyText: 'CtrlOrCommand+F',
|
||||||
|
testEnabled: () => getCurrentEditor() != null,
|
||||||
|
onClick: () => getCurrentEditor().find(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const matchingProps = ['conid', 'database', 'schemaName', 'pureName', 'objectTypeField'];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { getContext } from 'svelte';
|
||||||
|
|
||||||
|
import AceEditor from '../query/AceEditor.svelte';
|
||||||
|
import invalidateCommands from '../commands/invalidateCommands';
|
||||||
|
import createActivator, { getActiveComponent } from '../utility/createActivator';
|
||||||
|
import ToolStripContainer from '../buttons/ToolStripContainer.svelte';
|
||||||
|
import { useConnectionInfo } from '../utility/metadataLoaders';
|
||||||
|
import { extensions } from '../stores';
|
||||||
|
import { findEngineDriver } from 'dbgate-tools';
|
||||||
|
import registerCommand from '../commands/registerCommand';
|
||||||
|
import applyScriptTemplate, { getSupportedScriptTemplates } from '../utility/applyScriptTemplate';
|
||||||
|
import LoadingInfo from '../elements/LoadingInfo.svelte';
|
||||||
|
import ToolStripCommandButton from '../buttons/ToolStripCommandButton.svelte';
|
||||||
|
import SelectField from '../forms/SelectField.svelte';
|
||||||
|
import { changeTab } from '../utility/common';
|
||||||
|
|
||||||
|
export let tabid;
|
||||||
|
export let appObjectData;
|
||||||
|
export let scriptTemplate;
|
||||||
|
|
||||||
|
export let schemaName;
|
||||||
|
export let pureName;
|
||||||
|
export let conid;
|
||||||
|
export let database;
|
||||||
|
export let objectTypeField;
|
||||||
|
|
||||||
|
$: appObjectData = {
|
||||||
|
schemaName,
|
||||||
|
pureName,
|
||||||
|
conid,
|
||||||
|
database,
|
||||||
|
objectTypeField,
|
||||||
|
};
|
||||||
|
|
||||||
|
$: defaultScriptTemplate = getSupportedScriptTemplates(appObjectData.objectTypeField)?.[0]?.scriptTemplate;
|
||||||
|
|
||||||
|
$: connection = useConnectionInfo({ conid });
|
||||||
|
$: driver = findEngineDriver($connection, $extensions);
|
||||||
|
|
||||||
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
|
export const activator = createActivator('SqlObjectTab', false);
|
||||||
|
|
||||||
|
let domEditor;
|
||||||
|
let domToolStrip;
|
||||||
|
|
||||||
|
$: if ($tabFocused && domEditor) {
|
||||||
|
domEditor?.getEditor()?.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function find() {
|
||||||
|
domEditor.getEditor().execCommand('find');
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMenu() {
|
||||||
|
return [{ command: 'sqlObject.find' }];
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<ToolStripContainer>
|
||||||
|
{#await applyScriptTemplate(scriptTemplate ?? defaultScriptTemplate, $extensions, appObjectData)}
|
||||||
|
<LoadingInfo message="Loading script..." />
|
||||||
|
{:then sql}
|
||||||
|
<AceEditor
|
||||||
|
value={sql || ''}
|
||||||
|
readOnly
|
||||||
|
menu={createMenu()}
|
||||||
|
on:focus={() => {
|
||||||
|
activator.activate();
|
||||||
|
domToolStrip?.activate();
|
||||||
|
invalidateCommands();
|
||||||
|
}}
|
||||||
|
bind:this={domEditor}
|
||||||
|
mode={driver?.editorMode || 'sql'}
|
||||||
|
/>
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
<svelte:fragment slot="toolstrip">
|
||||||
|
<SelectField
|
||||||
|
isNative
|
||||||
|
value={scriptTemplate ?? defaultScriptTemplate}
|
||||||
|
options={getSupportedScriptTemplates(appObjectData.objectTypeField).map(x => ({
|
||||||
|
label: x.label,
|
||||||
|
value: x.scriptTemplate,
|
||||||
|
}))}
|
||||||
|
on:change={e => {
|
||||||
|
changeTab(tabid, tab => ({
|
||||||
|
...tab,
|
||||||
|
props: {
|
||||||
|
...tab.props,
|
||||||
|
scriptTemplate: e.detail,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</svelte:fragment>
|
||||||
|
</ToolStripContainer>
|
||||||
@@ -29,13 +29,13 @@
|
|||||||
|
|
||||||
export let tabid;
|
export let tabid;
|
||||||
|
|
||||||
const tabVisible: any = getContext('tabVisible');
|
const tabFocused: any = getContext('tabFocused');
|
||||||
|
|
||||||
export const activator = createActivator('YamlEditorTab', false);
|
export const activator = createActivator('YamlEditorTab', false);
|
||||||
|
|
||||||
let domEditor;
|
let domEditor;
|
||||||
|
|
||||||
$: if ($tabVisible && domEditor) {
|
$: if ($tabFocused && domEditor) {
|
||||||
domEditor?.getEditor()?.focus();
|
domEditor?.getEditor()?.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import * as ServerSummaryTab from './ServerSummaryTab.svelte';
|
|||||||
import * as ProfilerTab from './ProfilerTab.svelte';
|
import * as ProfilerTab from './ProfilerTab.svelte';
|
||||||
import * as DataDuplicatorTab from './DataDuplicatorTab.svelte';
|
import * as DataDuplicatorTab from './DataDuplicatorTab.svelte';
|
||||||
import * as ImportExportTab from './ImportExportTab.svelte';
|
import * as ImportExportTab from './ImportExportTab.svelte';
|
||||||
|
import * as SqlObjectTab from './SqlObjectTab.svelte';
|
||||||
|
|
||||||
import protabs from './index-pro';
|
import protabs from './index-pro';
|
||||||
|
|
||||||
@@ -62,5 +63,6 @@ export default {
|
|||||||
ProfilerTab,
|
ProfilerTab,
|
||||||
DataDuplicatorTab,
|
DataDuplicatorTab,
|
||||||
ImportExportTab,
|
ImportExportTab,
|
||||||
|
SqlObjectTab,
|
||||||
...protabs,
|
...protabs,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -63,3 +63,79 @@ export default async function applyScriptTemplate(scriptTemplate, extensions, pr
|
|||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getSupportedScriptTemplates(objectTypeField: string): { label: string; scriptTemplate: string }[] {
|
||||||
|
switch (objectTypeField) {
|
||||||
|
case 'tables':
|
||||||
|
return [
|
||||||
|
{ label: 'CREATE TABLE', scriptTemplate: 'CREATE TABLE' },
|
||||||
|
{ label: 'SELECT', scriptTemplate: 'SELECT' },
|
||||||
|
];
|
||||||
|
case 'views':
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'CREATE VIEW',
|
||||||
|
scriptTemplate: 'CREATE OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ALTER VIEW',
|
||||||
|
scriptTemplate: 'ALTER OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'CREATE TABLE',
|
||||||
|
scriptTemplate: 'CREATE TABLE',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'SELECT',
|
||||||
|
scriptTemplate: 'SELECT',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
case 'matviews':
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'CREATE MATERIALIZED VIEW',
|
||||||
|
scriptTemplate: 'CREATE OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ALTER MATERIALIZED VIEW',
|
||||||
|
scriptTemplate: 'ALTER OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'CREATE TABLE',
|
||||||
|
scriptTemplate: 'CREATE TABLE',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'SELECT',
|
||||||
|
scriptTemplate: 'SELECT',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'procedures':
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'CREATE PROCEDURE',
|
||||||
|
scriptTemplate: 'CREATE OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'ALTER PROCEDURE',
|
||||||
|
scriptTemplate: 'ALTER OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'EXECUTE',
|
||||||
|
scriptTemplate: 'EXECUTE PROCEDURE',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
case 'functions':
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
label: 'CREATE FUNCTION',
|
||||||
|
scriptTemplate: 'CREATE OBJECT',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: ' ALTER FUNCTION',
|
||||||
|
scriptTemplate: 'ALTER OBJECT',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,35 +1,81 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { currentDatabase, getCurrentDatabase, getLockedDatabaseMode, openedTabs } from '../stores';
|
import {
|
||||||
|
currentDatabase,
|
||||||
|
getActiveTab,
|
||||||
|
getCurrentDatabase,
|
||||||
|
getLockedDatabaseMode,
|
||||||
|
openedTabs,
|
||||||
|
selectedDatabaseObjectAppObject,
|
||||||
|
} from '../stores';
|
||||||
import { shouldShowTab } from '../tabpanel/TabsPanel.svelte';
|
import { shouldShowTab } from '../tabpanel/TabsPanel.svelte';
|
||||||
import { callWhenAppLoaded, getAppLoaded } from './appLoadManager';
|
import { callWhenAppLoaded, getAppLoaded } from './appLoadManager';
|
||||||
import { getConnectionInfo } from './metadataLoaders';
|
import { getConnectionInfo } from './metadataLoaders';
|
||||||
import { switchCurrentDatabase } from './common';
|
import { switchCurrentDatabase } from './common';
|
||||||
|
|
||||||
let lastCurrentTab = null;
|
// let lastCurrentTab = null;
|
||||||
|
|
||||||
openedTabs.subscribe(value => {
|
// openedTabs.subscribe(value => {
|
||||||
const newCurrentTab = (value || []).find(x => x.selected);
|
// const newCurrentTab = (value || []).find(x => x.selected);
|
||||||
if (newCurrentTab == lastCurrentTab) return;
|
// if (newCurrentTab == lastCurrentTab) return;
|
||||||
if (getLockedDatabaseMode() && getCurrentDatabase()) return;
|
// if (getLockedDatabaseMode() && getCurrentDatabase()) return;
|
||||||
|
|
||||||
const lastTab = lastCurrentTab;
|
// const lastTab = lastCurrentTab;
|
||||||
lastCurrentTab = newCurrentTab;
|
// lastCurrentTab = newCurrentTab;
|
||||||
// if (lastTab?.tabComponent == 'ConnectionTab') return;
|
// // if (lastTab?.tabComponent == 'ConnectionTab') return;
|
||||||
|
|
||||||
if (newCurrentTab) {
|
// if (newCurrentTab) {
|
||||||
const { conid, database } = newCurrentTab.props || {};
|
// const { conid, database } = newCurrentTab.props || {};
|
||||||
if (conid && database && (conid != lastTab?.props?.conid || database != lastTab?.props?.database)) {
|
// if (conid && database && (conid != lastTab?.props?.conid || database != lastTab?.props?.database)) {
|
||||||
const doWork = async () => {
|
// const doWork = async () => {
|
||||||
|
// const connection = await getConnectionInfo({ conid });
|
||||||
|
// switchCurrentDatabase({
|
||||||
|
// connection,
|
||||||
|
// name: database,
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
// callWhenAppLoaded(doWork);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
|
||||||
|
export async function handleAfterTabClick() {
|
||||||
|
const currentTab = getActiveTab();
|
||||||
|
const { conid, database, objectTypeField, pureName, schemaName, defaultActionId } = currentTab?.props || {};
|
||||||
|
const db = getCurrentDatabase();
|
||||||
|
if (conid && database && (conid != db?.connection?._id || database != db?.name)) {
|
||||||
const connection = await getConnectionInfo({ conid });
|
const connection = await getConnectionInfo({ conid });
|
||||||
switchCurrentDatabase({
|
switchCurrentDatabase({
|
||||||
connection,
|
connection,
|
||||||
name: database,
|
name: database,
|
||||||
});
|
});
|
||||||
};
|
// const doWork = async () => {
|
||||||
callWhenAppLoaded(doWork);
|
// const connection = await getConnectionInfo({ conid });
|
||||||
}
|
// switchCurrentDatabase({
|
||||||
|
// connection,
|
||||||
|
// name: database,
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
// callWhenAppLoaded(doWork);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (conid && database && objectTypeField && pureName && defaultActionId) {
|
||||||
|
selectedDatabaseObjectAppObject.set({
|
||||||
|
conid,
|
||||||
|
database,
|
||||||
|
objectTypeField,
|
||||||
|
pureName,
|
||||||
|
schemaName,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// focus current tab
|
||||||
|
openedTabs.update(tabs => {
|
||||||
|
return tabs.map(tab => ({
|
||||||
|
...tab,
|
||||||
|
focused: !!tab.selected && !tab.closedTime,
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
currentDatabase.subscribe(currentDb => {
|
currentDatabase.subscribe(currentDb => {
|
||||||
if (!getLockedDatabaseMode()) return;
|
if (!getLockedDatabaseMode()) return;
|
||||||
|
|||||||
@@ -30,10 +30,23 @@ export function markTabSaved(tabid) {
|
|||||||
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: false } : tab)));
|
openedTabs.update(files => files.map(tab => (tab.tabid == tabid ? { ...tab, unsaved: false } : tab)));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setSelectedTabFunc(files, tabid) {
|
export function setSelectedTabFunc(files, tabid, additionalProps = {}) {
|
||||||
return [
|
return [
|
||||||
...(files || []).filter(x => x.tabid != tabid).map(x => ({ ...x, selected: false })),
|
...(files || [])
|
||||||
...(files || []).filter(x => x.tabid == tabid).map(x => ({ ...x, selected: true })),
|
.filter(x => x.tabid != tabid)
|
||||||
|
.map(x => ({
|
||||||
|
...x,
|
||||||
|
selected: false,
|
||||||
|
focused: false,
|
||||||
|
})),
|
||||||
|
...(files || [])
|
||||||
|
.filter(x => x.tabid == tabid)
|
||||||
|
.map(x => ({
|
||||||
|
...x,
|
||||||
|
selected: true,
|
||||||
|
focused: false,
|
||||||
|
...additionalProps,
|
||||||
|
})),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default async function openNewTab(newTab, initialData: any = undefined, o
|
|||||||
let existing = null;
|
let existing = null;
|
||||||
|
|
||||||
const { savedFile, savedFolder, savedFilePath } = newTab.props || {};
|
const { savedFile, savedFolder, savedFilePath } = newTab.props || {};
|
||||||
|
const { tabPreviewMode } = newTab;
|
||||||
if (savedFile || savedFilePath) {
|
if (savedFile || savedFilePath) {
|
||||||
existing = oldTabs.find(
|
existing = oldTabs.find(
|
||||||
x =>
|
x =>
|
||||||
@@ -49,7 +50,9 @@ export default async function openNewTab(newTab, initialData: any = undefined, o
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
openedTabs.update(tabs => setSelectedTabFunc(tabs, existing.tabid));
|
openedTabs.update(tabs =>
|
||||||
|
setSelectedTabFunc(tabs, existing.tabid, !tabPreviewMode ? { tabPreviewMode: false } : {})
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +95,14 @@ export default async function openNewTab(newTab, initialData: any = undefined, o
|
|||||||
items.push(newItem);
|
items.push(newItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filesFiltered = tabPreviewMode ? (files || []).filter(x => !x.tabPreviewMode) : files;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...(files || []).map(x => ({ ...x, selected: false, tabOrder: _.findIndex(items, y => y.tabid == x.tabid) })),
|
...(filesFiltered || []).map(x => ({
|
||||||
|
...x,
|
||||||
|
selected: false,
|
||||||
|
tabOrder: _.findIndex(items, y => y.tabid == x.tabid),
|
||||||
|
})),
|
||||||
{
|
{
|
||||||
...newTab,
|
...newTab,
|
||||||
tabid,
|
tabid,
|
||||||
|
|||||||
111
packages/web/src/widgets/AppObjectListHandler.svelte
Normal file
111
packages/web/src/widgets/AppObjectListHandler.svelte
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import keycodes from '../utility/keycodes';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
export let list;
|
||||||
|
export let selectedObjectStore;
|
||||||
|
export let getSelectedObject;
|
||||||
|
export let selectedObjectMatcher;
|
||||||
|
export let module;
|
||||||
|
|
||||||
|
export let onScrollTop = null;
|
||||||
|
export let onFocusFilterBox = null;
|
||||||
|
|
||||||
|
let isListFocused = false;
|
||||||
|
let domDiv = null;
|
||||||
|
|
||||||
|
function handleKeyDown(ev) {
|
||||||
|
function selectByDiff(diff) {
|
||||||
|
const selected = getSelectedObject();
|
||||||
|
const index = _.findIndex(list, x => selectedObjectMatcher(x, selected));
|
||||||
|
|
||||||
|
if (index == 0 && diff < 0) {
|
||||||
|
onFocusFilterBox?.();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= 0) {
|
||||||
|
let newIndex = index + diff;
|
||||||
|
if (newIndex >= list.length) {
|
||||||
|
newIndex = list.length - 1;
|
||||||
|
}
|
||||||
|
if (newIndex < 0) {
|
||||||
|
newIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list[newIndex]) {
|
||||||
|
selectedObjectStore.set(list[newIndex]);
|
||||||
|
module.handleObjectClick(list[newIndex], { tabPreviewMode: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newIndex == 0) {
|
||||||
|
onScrollTop?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.upArrow) {
|
||||||
|
selectByDiff(-1);
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.downArrow) {
|
||||||
|
selectByDiff(1);
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.enter) {
|
||||||
|
module.handleObjectClick(getSelectedObject(), { tabPreviewMode: false, focusTab: true });
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.pageDown) {
|
||||||
|
selectByDiff(10);
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.pageUp) {
|
||||||
|
selectByDiff(-10);
|
||||||
|
ev.preventDefault();
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.home) {
|
||||||
|
if (list[0]) {
|
||||||
|
selectedObjectStore.set(list[0]);
|
||||||
|
module.handleObjectClick(list[0], { tabPreviewMode: true });
|
||||||
|
onScrollTop?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ev.keyCode == keycodes.end) {
|
||||||
|
if (list[list.length - 1]) {
|
||||||
|
selectedObjectStore.set(list[list.length - 1]);
|
||||||
|
module.handleObjectClick(list[list.length - 1], { tabPreviewMode: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function focusFirst() {
|
||||||
|
domDiv?.focus();
|
||||||
|
if (list[0]) {
|
||||||
|
selectedObjectStore.set(list[0]);
|
||||||
|
module.handleObjectClick(list[0], { tabPreviewMode: true });
|
||||||
|
onScrollTop?.();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
tabindex="0"
|
||||||
|
on:keydown={handleKeyDown}
|
||||||
|
class="wrapper"
|
||||||
|
class:app-object-list-focused={isListFocused}
|
||||||
|
on:focus={() => {
|
||||||
|
isListFocused = true;
|
||||||
|
}}
|
||||||
|
on:blur={() => {
|
||||||
|
isListFocused = false;
|
||||||
|
}}
|
||||||
|
bind:this={domDiv}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wrapper:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -36,18 +36,28 @@
|
|||||||
import FontIcon from '../icons/FontIcon.svelte';
|
import FontIcon from '../icons/FontIcon.svelte';
|
||||||
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
|
import CloseSearchButton from '../buttons/CloseSearchButton.svelte';
|
||||||
import { findEngineDriver } from 'dbgate-tools';
|
import { findEngineDriver } from 'dbgate-tools';
|
||||||
import { currentDatabase, extensions } from '../stores';
|
import {
|
||||||
|
currentDatabase,
|
||||||
|
extensions,
|
||||||
|
getSelectedDatabaseObjectAppObject,
|
||||||
|
selectedDatabaseObjectAppObject,
|
||||||
|
} from '../stores';
|
||||||
import newQuery from '../query/newQuery';
|
import newQuery from '../query/newQuery';
|
||||||
import runCommand from '../commands/runCommand';
|
import runCommand from '../commands/runCommand';
|
||||||
import { apiCall } from '../utility/api';
|
import { apiCall } from '../utility/api';
|
||||||
import { filterAppsForDatabase } from '../utility/appTools';
|
import { filterAppsForDatabase } from '../utility/appTools';
|
||||||
import SchemaSelector from './SchemaSelector.svelte';
|
import SchemaSelector from './SchemaSelector.svelte';
|
||||||
import { appliedCurrentSchema } from '../stores';
|
import { appliedCurrentSchema } from '../stores';
|
||||||
|
import AppObjectListHandler from './AppObjectListHandler.svelte';
|
||||||
|
import { matchDatabaseObjectAppObject } from '../appobj/appObjectTools';
|
||||||
|
|
||||||
export let conid;
|
export let conid;
|
||||||
export let database;
|
export let database;
|
||||||
|
|
||||||
let filter = '';
|
let filter = '';
|
||||||
|
let domContainer = null;
|
||||||
|
let domFilter = null;
|
||||||
|
let domListHandler;
|
||||||
|
|
||||||
$: objects = useDatabaseInfo({ conid, database });
|
$: objects = useDatabaseInfo({ conid, database });
|
||||||
$: status = useDatabaseStatus({ conid, database });
|
$: status = useDatabaseStatus({ conid, database });
|
||||||
@@ -151,7 +161,14 @@
|
|||||||
</WidgetsInnerContainer>
|
</WidgetsInnerContainer>
|
||||||
{:else}
|
{:else}
|
||||||
<SearchBoxWrapper>
|
<SearchBoxWrapper>
|
||||||
<SearchInput placeholder="Search in tables, objects, # prefix in columns" bind:value={filter} />
|
<SearchInput
|
||||||
|
placeholder="Search in tables, objects, # prefix in columns"
|
||||||
|
bind:value={filter}
|
||||||
|
bind:this={domFilter}
|
||||||
|
onFocusFilteredList={() => {
|
||||||
|
domListHandler?.focusFirst();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
<CloseSearchButton bind:filter />
|
<CloseSearchButton bind:filter />
|
||||||
<DropDownButton icon="icon plus-thick" menu={createAddMenu} />
|
<DropDownButton icon="icon plus-thick" menu={createAddMenu} />
|
||||||
<InlineButton on:click={handleRefreshDatabase} title="Refresh database connection and object list" square>
|
<InlineButton on:click={handleRefreshDatabase} title="Refresh database connection and object list" square>
|
||||||
@@ -168,10 +185,24 @@
|
|||||||
negativeMarginTop
|
negativeMarginTop
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<WidgetsInnerContainer>
|
<WidgetsInnerContainer bind:this={domContainer}>
|
||||||
{#if ($status && ($status.name == 'pending' || $status.name == 'checkStructure' || $status.name == 'loadStructure') && $objects) || !$objects}
|
{#if ($status && ($status.name == 'pending' || $status.name == 'checkStructure' || $status.name == 'loadStructure') && $objects) || !$objects}
|
||||||
<LoadingInfo message={$status?.feedback?.analysingMessage || 'Loading database structure'} />
|
<LoadingInfo message={$status?.feedback?.analysingMessage || 'Loading database structure'} />
|
||||||
{:else}
|
{:else}
|
||||||
|
<AppObjectListHandler
|
||||||
|
bind:this={domListHandler}
|
||||||
|
list={flatFilteredList.map(x => ({ ...x, conid, database }))}
|
||||||
|
selectedObjectStore={selectedDatabaseObjectAppObject}
|
||||||
|
getSelectedObject={getSelectedDatabaseObjectAppObject}
|
||||||
|
selectedObjectMatcher={matchDatabaseObjectAppObject}
|
||||||
|
module={databaseObjectAppObject}
|
||||||
|
onScrollTop={() => {
|
||||||
|
domContainer?.scrollTop();
|
||||||
|
}}
|
||||||
|
onFocusFilterBox={() => {
|
||||||
|
domFilter?.focus();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<AppObjectList
|
<AppObjectList
|
||||||
list={objectList
|
list={objectList
|
||||||
.filter(x => ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true))
|
.filter(x => ($appliedCurrentSchema ? x.schemaName == $appliedCurrentSchema : true))
|
||||||
@@ -189,6 +220,7 @@
|
|||||||
hideSchemaName: !!$appliedCurrentSchema,
|
hideSchemaName: !!$appliedCurrentSchema,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
</AppObjectListHandler>
|
||||||
{/if}
|
{/if}
|
||||||
</WidgetsInnerContainer>
|
</WidgetsInnerContainer>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
<div on:drop><slot /></div>
|
<script lang="ts">
|
||||||
|
let domDiv;
|
||||||
|
|
||||||
|
export function scrollTop() {
|
||||||
|
domDiv.scrollTop = 0;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div on:drop bind:this={domDiv}><slot /></div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
div {
|
div {
|
||||||
|
|||||||
Reference in New Issue
Block a user