Merge pull request #751 from dbeaver/feat/save-lob

feat(plugin-data-spreadsheet-new): CB-1887 save LOB content
This commit is contained in:
Alexey
2022-04-07 13:06:09 +03:00
committed by GitHub
9 changed files with 183 additions and 8 deletions
@@ -0,0 +1,9 @@
mutation getResultsetDataURL($connectionId: ID!, $contextId: ID!, $resultsId: ID!, $lobColumnIndex: ID!, $row: [ SQLResultRow! ]) {
url: readLobValue(
connectionId: $connectionId,
contextId: $contextId,
resultsId: $resultsId,
lobColumnIndex: $lobColumnIndex,
row: $row
)
}
+36
View File
@@ -225,6 +225,7 @@ export interface DatabaseAuthModel {
icon?: Maybe<Scalars['String']>;
id: Scalars['ID'];
properties: Array<ObjectPropertyInfo>;
requiresLocalConfiguration?: Maybe<Scalars['Boolean']>;
}
export interface DatabaseCatalog {
@@ -328,6 +329,7 @@ export interface Mutation {
/** @deprecated Field no longer supported */
openConnection: ConnectionInfo;
openSession: SessionInfo;
readLobValue: Scalars['String'];
refreshSessionConnections?: Maybe<Scalars['Boolean']>;
setConnectionNavigatorSettings: ConnectionInfo;
setUserConfigurationParameter: Scalars['Boolean'];
@@ -459,6 +461,15 @@ export interface MutationOpenSessionArgs {
}
export interface MutationReadLobValueArgs {
connectionId: Scalars['ID'];
contextId: Scalars['ID'];
lobColumnIndex: Scalars['ID'];
resultsId: Scalars['ID'];
row?: InputMaybe<Array<SqlResultRow>>;
}
export interface MutationSetConnectionNavigatorSettingsArgs {
id: Scalars['ID'];
settings: NavigatorSettingsInput;
@@ -1980,6 +1991,17 @@ export type CloseResultMutationVariables = Exact<{
export type CloseResultMutation = { result: boolean };
export type GetResultsetDataUrlMutationVariables = Exact<{
connectionId: Scalars['ID'];
contextId: Scalars['ID'];
resultsId: Scalars['ID'];
lobColumnIndex: Scalars['ID'];
row?: InputMaybe<Array<SqlResultRow> | SqlResultRow>;
}>;
export type GetResultsetDataUrlMutation = { url: string };
export type GetSqlExecuteTaskResultsMutationVariables = Exact<{
taskId: Scalars['ID'];
}>;
@@ -3163,6 +3185,17 @@ export const CloseResultDocument = `
)
}
`;
export const GetResultsetDataUrlDocument = `
mutation getResultsetDataURL($connectionId: ID!, $contextId: ID!, $resultsId: ID!, $lobColumnIndex: ID!, $row: [SQLResultRow!]) {
url: readLobValue(
connectionId: $connectionId
contextId: $contextId
resultsId: $resultsId
lobColumnIndex: $lobColumnIndex
row: $row
)
}
`;
export const GetSqlExecuteTaskResultsDocument = `
mutation getSqlExecuteTaskResults($taskId: ID!) {
result: asyncSqlExecuteResults(taskId: $taskId) {
@@ -3742,6 +3775,9 @@ export function getSdk(client: GraphQLClient, withWrapper: SdkFunctionWrapper =
closeResult(variables: CloseResultMutationVariables, requestHeaders?: Dom.RequestInit['headers']): Promise<CloseResultMutation> {
return withWrapper(wrappedRequestHeaders => client.request<CloseResultMutation>(CloseResultDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'closeResult', 'mutation');
},
getResultsetDataURL(variables: GetResultsetDataUrlMutationVariables, requestHeaders?: Dom.RequestInit['headers']): Promise<GetResultsetDataUrlMutation> {
return withWrapper(wrappedRequestHeaders => client.request<GetResultsetDataUrlMutation>(GetResultsetDataUrlDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getResultsetDataURL', 'mutation');
},
getSqlExecuteTaskResults(variables: GetSqlExecuteTaskResultsMutationVariables, requestHeaders?: Dom.RequestInit['headers']): Promise<GetSqlExecuteTaskResultsMutation> {
return withWrapper(wrappedRequestHeaders => client.request<GetSqlExecuteTaskResultsMutation>(GetSqlExecuteTaskResultsDocument, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'getSqlExecuteTaskResults', 'mutation');
},
+2 -2
View File
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
export function download(blob: Blob, fileName: string): void {
export function download(content: Blob | string, fileName = ''): void {
const saveLink = document.createElement('a');
saveLink.tabIndex = -1;
@@ -15,7 +15,7 @@ export function download(blob: Blob, fileName: string): void {
document.body.appendChild(saveLink);
try {
const url = URL.createObjectURL(blob);
const url = typeof content === 'string' ? content : URL.createObjectURL(content);
saveLink.href = url;
saveLink.onclick = () => requestAnimationFrame(() => URL.revokeObjectURL(url));
} catch (e: any) {
@@ -0,0 +1,58 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2022 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { injectable } from '@cloudbeaver/core-di';
import { download } from '@cloudbeaver/core-utils';
import { DataViewerContentSaverService } from '@cloudbeaver/plugin-data-viewer';
import { DataGridContextMenuService } from './DataGridContextMenuService';
@injectable()
export class DataGridContextMenuSaveContentService {
private static readonly menuContentSaveToken = 'menuContentSave';
constructor(
private readonly dataGridContextMenuService: DataGridContextMenuService,
private readonly dataViewerContentSaverService: DataViewerContentSaverService
) { }
getMenuContentSaveToken(): string {
return DataGridContextMenuSaveContentService.menuContentSaveToken;
}
register(): void {
this.dataGridContextMenuService.add(
this.dataGridContextMenuService.getMenuToken(),
{
id: this.getMenuContentSaveToken(),
order: 4,
title: 'ui_processing_save',
icon: '/icons/save.svg',
isPresent(context) {
return context.contextType === DataGridContextMenuService.cellContext;
},
onClick: async context => {
const url = await this.dataViewerContentSaverService.getElementValueURL(
context.data.model,
context.data.resultIndex,
context.data.key
);
if (url) {
download(url);
}
},
isHidden: context => !this.dataViewerContentSaverService.canSaveElementValue(
context.data.model,
context.data.resultIndex,
context.data.key
),
}
);
}
}
@@ -14,6 +14,7 @@ import { DataPresentationService } from '@cloudbeaver/plugin-data-viewer';
import { DataGridContextMenuCellEditingService } from './DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService';
import { DataGridContextMenuFilterService } from './DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService';
import { DataGridContextMenuOrderService } from './DataGrid/DataGridContextMenu/DataGridContextMenuOrderService';
import { DataGridContextMenuSaveContentService } from './DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService';
import { DataGridContextMenuService } from './DataGrid/DataGridContextMenu/DataGridContextMenuService';
import { DataGridSettingsService } from './DataGridSettingsService';
import { SpreadsheetGrid } from './SpreadsheetGrid';
@@ -21,12 +22,13 @@ import { SpreadsheetGrid } from './SpreadsheetGrid';
@injectable()
export class SpreadsheetBootstrap extends Bootstrap {
constructor(
private dataPresentationService: DataPresentationService,
private dataGridSettingsService: DataGridSettingsService,
private dataGridContextMenuSortingService: DataGridContextMenuOrderService,
private dataGridContextMenuFilterService: DataGridContextMenuFilterService,
private dataGridContextMenuCellEditingService: DataGridContextMenuCellEditingService,
private dataGridContextMenuService: DataGridContextMenuService,
private readonly dataPresentationService: DataPresentationService,
private readonly dataGridSettingsService: DataGridSettingsService,
private readonly dataGridContextMenuSortingService: DataGridContextMenuOrderService,
private readonly dataGridContextMenuFilterService: DataGridContextMenuFilterService,
private readonly dataGridContextMenuCellEditingService: DataGridContextMenuCellEditingService,
private readonly dataGridContextMenuService: DataGridContextMenuService,
private readonly dataGridContextMenuSaveContentService: DataGridContextMenuSaveContentService,
exceptionsCatcherService: ExceptionsCatcherService
) {
super();
@@ -45,6 +47,7 @@ export class SpreadsheetBootstrap extends Bootstrap {
this.dataGridContextMenuSortingService.register();
this.dataGridContextMenuFilterService.register();
this.dataGridContextMenuCellEditingService.register();
this.dataGridContextMenuSaveContentService.register();
this.dataGridContextMenuService.add(
this.dataGridContextMenuService.getMenuToken(),
@@ -11,6 +11,7 @@ import type { PluginManifest } from '@cloudbeaver/core-di';
import { DataGridContextMenuCellEditingService } from './DataGrid/DataGridContextMenu/DataGridContextMenuCellEditingService';
import { DataGridContextMenuFilterService } from './DataGrid/DataGridContextMenu/DataGridContextMenuFilter/DataGridContextMenuFilterService';
import { DataGridContextMenuOrderService } from './DataGrid/DataGridContextMenu/DataGridContextMenuOrderService';
import { DataGridContextMenuSaveContentService } from './DataGrid/DataGridContextMenu/DataGridContextMenuSaveContentService';
import { DataGridContextMenuService } from './DataGrid/DataGridContextMenu/DataGridContextMenuService';
import { DataGridSettingsService } from './DataGridSettingsService';
import { LocaleService } from './LocaleService';
@@ -26,5 +27,6 @@ export const manifest: PluginManifest = {
DataGridContextMenuOrderService,
DataGridContextMenuFilterService,
DataGridContextMenuCellEditingService,
DataGridContextMenuSaveContentService,
],
};
@@ -0,0 +1,64 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2022 DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import { injectable } from '@cloudbeaver/core-di';
import { GraphQLService } from '@cloudbeaver/core-sdk';
import type { IResultSetElementKey } from './DatabaseDataModel/Actions/ResultSet/IResultSetDataKey';
import { isResultSetContentValue } from './DatabaseDataModel/Actions/ResultSet/isResultSetContentValue';
import { ResultSetDataAction } from './DatabaseDataModel/Actions/ResultSet/ResultSetDataAction';
import { ResultSetViewAction } from './DatabaseDataModel/Actions/ResultSet/ResultSetViewAction';
import type { IDatabaseDataModel } from './DatabaseDataModel/IDatabaseDataModel';
const RESULT_VALUE_URL = '/api/sql-result-value';
@injectable()
export class DataViewerContentSaverService {
constructor(
private readonly graphQLService: GraphQLService
) { }
canSaveElementValue(
model: IDatabaseDataModel,
resultIndex: number,
element: IResultSetElementKey
) {
const view = model.source.getAction(resultIndex, ResultSetViewAction);
const cellValue = view.getCellValue(element);
return isResultSetContentValue(cellValue);
}
async getElementValueURL(
model: IDatabaseDataModel,
resultIndex: number,
element: IResultSetElementKey
) {
const result = model.getResult(resultIndex);
const data = model.source.getAction(resultIndex, ResultSetDataAction);
const column = data.getColumn(element.column);
const row = data.getRowValue(element.row);
if (!result?.id || !row || !column) {
return;
}
const response = await this.graphQLService.sdk.getResultsetDataURL({
resultsId: result.id,
connectionId: result.connectionId,
contextId: result.contextId,
lobColumnIndex: String(column.position),
row: {
data: row,
},
});
return `${RESULT_VALUE_URL}/${response.url}`;
}
}
@@ -38,6 +38,7 @@ export * from './DatabaseDataModel/IDatabaseDataSource';
export * from './DatabaseDataModel/IDatabaseResultSet';
export * from './DatabaseDataModel/Order';
export * from './DataViewerService';
export * from './DataViewerContentSaverService';
// All Services and Components that is provided by this plugin should be exported here
export * from './TableViewer/TableViewerStorageService';
@@ -10,6 +10,7 @@ import type { PluginManifest } from '@cloudbeaver/core-di';
import { DataPresentationService } from './DataPresentationService';
import { DataViewerBootstrap } from './DataViewerBootstrap';
import { DataViewerContentSaverService } from './DataViewerContentSaverService';
import { DataViewerDataChangeConfirmationService } from './DataViewerDataChangeConfirmationService';
import { DataViewerService } from './DataViewerService';
import { DataViewerSettingsService } from './DataViewerSettingsService';
@@ -51,5 +52,6 @@ export const manifest: PluginManifest = {
DataValuePanelBootstrap,
DataViewerSettingsService,
DataViewerService,
DataViewerContentSaverService,
],
};