diff --git a/webapp/packages/plugin-data-spreadsheet-new/package.json b/webapp/packages/plugin-data-spreadsheet-new/package.json index a5e89776c8..80b9ae3cf6 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/package.json +++ b/webapp/packages/plugin-data-spreadsheet-new/package.json @@ -30,6 +30,7 @@ "@cloudbeaver/core-dialogs": "workspace:*", "@cloudbeaver/core-events": "workspace:*", "@cloudbeaver/core-localization": "workspace:*", + "@cloudbeaver/core-navigation-tree": "workspace:*", "@cloudbeaver/core-sdk": "workspace:*", "@cloudbeaver/core-settings": "workspace:*", "@cloudbeaver/core-ui": "workspace:*", diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuGenerateSqlService.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuGenerateSqlService.ts index cbc0cf97c3..7e80a0cc1e 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuGenerateSqlService.ts +++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGrid/DataGridContextMenu/DataGridContextMenuGenerateSqlService.ts @@ -8,7 +8,9 @@ import { injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; +import { LocalizationService } from '@cloudbeaver/core-localization'; import { SqlResultSetGeneratorId, type SqlQueryGeneratorOptions, type SqlResultRow } from '@cloudbeaver/core-sdk'; +import { NavNodeInfoResource } from '@cloudbeaver/core-navigation-tree'; import { ActionService, MenuService, type IAction } from '@cloudbeaver/core-view'; import { DATA_CONTEXT_DV_DDM, @@ -42,7 +44,15 @@ import type { IDataContextProvider } from '@cloudbeaver/core-data-context'; import { getDefaultQueryGeneratorOptions, GeneratedSqlDialog, SqlGeneratorsResource, DDL_GENERATOR_ID } from '@cloudbeaver/plugin-sql-generator'; import { isNotNullDefined } from '@dbeaver/js-helpers'; -@injectable(() => [ActionService, MenuService, CommonDialogService, NotificationService, SqlGeneratorsResource]) +@injectable(() => [ + ActionService, + MenuService, + CommonDialogService, + NotificationService, + SqlGeneratorsResource, + LocalizationService, + NavNodeInfoResource, +]) export class DataGridContextMenuGenerateSqlService { constructor( private readonly actionService: ActionService, @@ -50,6 +60,8 @@ export class DataGridContextMenuGenerateSqlService { private readonly commonDialogService: CommonDialogService, private readonly notificationService: NotificationService, private readonly sqlGenerationResource: SqlGeneratorsResource, + private readonly localizationService: LocalizationService, + private readonly navNodeInfoResource: NavNodeInfoResource, ) {} register(): void { @@ -107,21 +119,22 @@ export class DataGridContextMenuGenerateSqlService { return; } - await this.openSqlDialog(context, mapGeneratorIdFromAction(action)); + await this.openSqlDialog(context, mapGeneratorIdFromAction(action), action.info.label); }, }); } - private async openSqlDialog(context: IDataContextProvider, generatorId: SqlResultSetGeneratorId): Promise { + private async openSqlDialog(context: IDataContextProvider, generatorId: SqlResultSetGeneratorId, generatorLabel: string): Promise { const model = context.get(DATA_CONTEXT_DV_DDM)!; const resultIndex = context.get(DATA_CONTEXT_DV_DDM_RESULT_INDEX)!; const key = context.get(DATA_CONTEXT_DV_RESULT_KEY); + const options = model.source.options as IDataContainerOptions | undefined; + const containerNodePath = options?.containerNodePath; if (!isResultSetDataModel(model)) { return; } - const options = model.source.options as IDataContainerOptions | undefined; const nodePath = options?.containerNodePath; const select = model.source.tryGetAction(resultIndex, IDatabaseDataSelectAction, GridSelectAction); const projectId = model.source.executionContext?.context?.projectId; @@ -165,6 +178,8 @@ export class DataGridContextMenuGenerateSqlService { await this.commonDialogService.open(GeneratedSqlDialog, { query, nodeId: nodePath ?? connectionId, + nodeName: this.getEntityNameFromNodePath(containerNodePath, model.name), + generatorName: this.localizationService.translate(generatorLabel), options: getDefaultQueryGeneratorOptions(), regenerateQuery: options => this.generateQuery({ @@ -218,6 +233,8 @@ export class DataGridContextMenuGenerateSqlService { await this.commonDialogService.open(GeneratedSqlDialog, { query, nodeId: nodePathList, + nodeName: this.getEntityNameFromNodePath(nodePathList, model.name), + generatorName: createGenerator.label, options: getDefaultQueryGeneratorOptions(), regenerateQuery: genOptions => this.sqlGenerationResource.generateEntityQuery(createGenerator.id, nodePathList, genOptions), }); @@ -259,6 +276,18 @@ export class DataGridContextMenuGenerateSqlService { return query; } + + private getEntityNameFromNodePath(nodePath: string | undefined, fallbackName?: string | null): string | undefined { + if (nodePath) { + const name = this.navNodeInfoResource.get(nodePath)?.name; + + if (name) { + return name; + } + } + + return fallbackName ?? undefined; + } } function mapGeneratorIdFromAction(action: IAction): SqlResultSetGeneratorId { diff --git a/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json b/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json index 19ff9f0ee4..70bdb722c7 100644 --- a/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json +++ b/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json @@ -49,6 +49,9 @@ { "path": "../core-localization" }, + { + "path": "../core-navigation-tree" + }, { "path": "../core-sdk" }, diff --git a/webapp/packages/plugin-sql-generator/src/SqlGenerators/GeneratedSqlDialog.tsx b/webapp/packages/plugin-sql-generator/src/SqlGenerators/GeneratedSqlDialog.tsx index 72fd627022..e448a1061f 100644 --- a/webapp/packages/plugin-sql-generator/src/SqlGenerators/GeneratedSqlDialog.tsx +++ b/webapp/packages/plugin-sql-generator/src/SqlGenerators/GeneratedSqlDialog.tsx @@ -23,6 +23,7 @@ import { import { ConnectionDialectResource, ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections'; import { useService } from '@cloudbeaver/core-di'; import type { DialogComponentProps } from '@cloudbeaver/core-dialogs'; +import { download, withTimestamp } from '@cloudbeaver/core-utils'; import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree'; import { useCodemirrorExtensions } from '@cloudbeaver/plugin-codemirror6'; import { SqlEditorNavigatorService } from '@cloudbeaver/plugin-sql-editor-navigation-tab'; @@ -34,6 +35,8 @@ import type { SqlQueryGeneratorOptions } from '@cloudbeaver/core-sdk'; interface Payload { nodeId: string; + nodeName?: string; + generatorName?: string; query: string; options?: SqlQueryGeneratorOptions; regenerateQuery: (options: SqlQueryGeneratorOptions) => Promise; @@ -110,6 +113,13 @@ export const GeneratedSqlDialog = observer>(functi } } + function handleSaveToFile() { + const blob = new Blob([state.query], { type: 'application/sql' }); + const name = [payload.nodeName, payload.generatorName].join('-') || 'Generated'; + + download(blob, `${withTimestamp(name)}.sql`); + } + return ( @@ -141,14 +151,31 @@ export const GeneratedSqlDialog = observer>(functi /> -
- - - +
+
+
+
+ + +
diff --git a/webapp/packages/plugin-sql-generator/src/SqlGenerators/SqlGeneratorsBootstrap.ts b/webapp/packages/plugin-sql-generator/src/SqlGenerators/SqlGeneratorsBootstrap.ts index 70bcfea020..ee4d5385de 100644 --- a/webapp/packages/plugin-sql-generator/src/SqlGenerators/SqlGeneratorsBootstrap.ts +++ b/webapp/packages/plugin-sql-generator/src/SqlGenerators/SqlGeneratorsBootstrap.ts @@ -85,6 +85,8 @@ export class SqlGeneratorsBootstrap extends Bootstrap { await this.commonDialogService.open(GeneratedSqlDialog, { query, nodeId: node.uri, + nodeName: node.name, + generatorName: action.label, options: getDefaultQueryGeneratorOptions(), regenerateQuery: options => this.sqlGeneratorsResource.generateEntityQuery(action.id, node.uri, options), }); diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 466d07e3af..a7ff65cc12 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -3049,6 +3049,7 @@ __metadata: "@cloudbeaver/core-dialogs": "workspace:*" "@cloudbeaver/core-events": "workspace:*" "@cloudbeaver/core-localization": "workspace:*" + "@cloudbeaver/core-navigation-tree": "workspace:*" "@cloudbeaver/core-sdk": "workspace:*" "@cloudbeaver/core-settings": "workspace:*" "@cloudbeaver/core-ui": "workspace:*"