mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-10-28 03:24:29 +08:00
chore: remastered build system
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/lib
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env*
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@cloudbeaver/plugin-data-export",
|
||||
"version": "0.1.0",
|
||||
"description": "",
|
||||
"license": "Apache-2.0",
|
||||
"main": "lib/index.js",
|
||||
"module": "lib/index.js",
|
||||
"scripts": {
|
||||
"prebuild": "rimraf lib/*",
|
||||
"build": "webpack --config ../../configs/webpack.plugin.config",
|
||||
"postbuild": "tsc",
|
||||
"lint": "eslint ./src/ --ext .ts,.tsx",
|
||||
"lint-fix": "eslint ./src/ --ext .ts,.tsx --fix"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@cloudbeaver/plugin-data-viewer": "^0.1.0",
|
||||
"@cloudbeaver/core-app": "^0.1.0",
|
||||
"@cloudbeaver/core-blocks": "^0.1.0",
|
||||
"@cloudbeaver/core-di": "^0.1.0",
|
||||
"@cloudbeaver/core-dialogs": "^0.1.0",
|
||||
"@cloudbeaver/core-events": "^0.1.0",
|
||||
"@cloudbeaver/core-extensions": "^0.1.0",
|
||||
"@cloudbeaver/core-localization": "^0.1.0",
|
||||
"@cloudbeaver/core-plugin": "^0.1.0",
|
||||
"@cloudbeaver/core-product": "^0.1.0",
|
||||
"@cloudbeaver/core-root": "^0.1.0",
|
||||
"@cloudbeaver/core-sdk": "^0.1.0",
|
||||
"@cloudbeaver/core-settings": "^0.1.0",
|
||||
"@cloudbeaver/core-theming": "^0.1.0",
|
||||
"@cloudbeaver/core-utils": "^0.1.0",
|
||||
"react": "^16.x.x",
|
||||
"rxjs": "^6.x.x",
|
||||
"mobx": "^5.x.x",
|
||||
"mobx-react": "^6.x.x",
|
||||
"reshadow": "^0.0.1-alpha.78"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { DataExportMenuService } from './DataExportMenuService';
|
||||
|
||||
@injectable()
|
||||
export class Bootstrap {
|
||||
constructor(private dataExportMenuService: DataExportMenuService) { }
|
||||
|
||||
bootstrap() {
|
||||
this.dataExportMenuService.register();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 {
|
||||
NavigationTreeContextMenuService, NodeManagerUtils, NavNode, EObjectFeature
|
||||
} from '@cloudbeaver/core-app';
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import {
|
||||
IContextMenuItem, IMenuContext, CommonDialogService, ContextMenuService
|
||||
} from '@cloudbeaver/core-dialogs';
|
||||
import { TableFooterMenuService, TableViewerModel } from '@cloudbeaver/plugin-data-viewer';
|
||||
|
||||
import { DataExportDialog } from './Dialog/DataExportDialog';
|
||||
|
||||
@injectable()
|
||||
export class DataExportMenuService {
|
||||
constructor(
|
||||
private commonDialogService: CommonDialogService,
|
||||
private tableFooterMenuService: TableFooterMenuService,
|
||||
private contextMenuService: ContextMenuService,
|
||||
) { }
|
||||
|
||||
register() {
|
||||
const exportData: IContextMenuItem<TableViewerModel> = {
|
||||
id: 'export ',
|
||||
isPresent(context) {
|
||||
return context.contextType === TableFooterMenuService.nodeContextType;
|
||||
},
|
||||
order: 1,
|
||||
title: 'Export',
|
||||
icon: 'export',
|
||||
onClick: this.exportData.bind(this),
|
||||
};
|
||||
this.tableFooterMenuService.registerMenuItem(exportData);
|
||||
|
||||
this.contextMenuService.addMenuItem<NavNode>(
|
||||
this.contextMenuService.getRootMenuToken(),
|
||||
{
|
||||
id: 'export',
|
||||
isPresent(context) {
|
||||
return context.contextType === NavigationTreeContextMenuService.nodeContextType
|
||||
&& context.data.objectFeatures.includes(EObjectFeature.dataContainer);
|
||||
},
|
||||
order: 2,
|
||||
title: 'Export',
|
||||
onClick: (context) => {
|
||||
const node = context.data;
|
||||
const connectionId = NodeManagerUtils.nodeIdToConnectionId(node.id);
|
||||
this.commonDialogService.open(DataExportDialog, {
|
||||
connectionId,
|
||||
containerNodePath: node.id,
|
||||
});
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private exportData(context: IMenuContext<TableViewerModel>) {
|
||||
this.commonDialogService.open(DataExportDialog, {
|
||||
connectionId: context.data.connectionId,
|
||||
contextId: context.data.executionContext?.contextId,
|
||||
containerNodePath: context.data.containerNodePath,
|
||||
resultId: context.data.resultId,
|
||||
sourceName: context.data.sourceName,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { GraphQLService, DataTransferParameters } from '@cloudbeaver/core-sdk';
|
||||
import { Deferred, OrderedMap } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { ExportFromContainerProcess } from './ExportFromContainerProcess';
|
||||
import { ExportFromResultsProcess } from './ExportFromResultsProcess';
|
||||
import { IExportContext } from './IExportContext';
|
||||
|
||||
type Process = {
|
||||
taskId: string;
|
||||
process: Deferred<string>;
|
||||
}
|
||||
|
||||
type ExportProcess = {
|
||||
taskId: string;
|
||||
context: IExportContext;
|
||||
parameters: DataTransferParameters;
|
||||
process: Deferred<string>;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class DataExportProcessService {
|
||||
readonly exportProcesses = new OrderedMap<string, ExportProcess>(value => value.taskId);
|
||||
|
||||
constructor(
|
||||
private graphQLService: GraphQLService,
|
||||
private notificationService: NotificationService,
|
||||
) { }
|
||||
|
||||
async cancel(exportId: string) {
|
||||
const process = this.exportProcesses.get(exportId);
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
process.process.cancel();
|
||||
}
|
||||
|
||||
async delete(exportId: string) {
|
||||
const process = this.exportProcesses.get(exportId);
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const dataFileId = process.process.getPayload();
|
||||
if (dataFileId) {
|
||||
await this.graphQLService.gql.removeDataTransferFile({ dataFileId });
|
||||
}
|
||||
} catch (exception) {
|
||||
this.notificationService.logException(exception, 'Error occurred while deleting file');
|
||||
} finally {
|
||||
this.exportProcesses.remove(exportId);
|
||||
}
|
||||
}
|
||||
|
||||
download(exportId: string) {
|
||||
const process = this.exportProcesses.get(exportId);
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
const dataFileId = process.process.getPayload();
|
||||
if (!dataFileId) {
|
||||
return;
|
||||
}
|
||||
this.exportProcesses.remove(exportId);
|
||||
}
|
||||
|
||||
downloadUrl(exportId: string) {
|
||||
const process = this.exportProcesses.get(exportId);
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
const dataFileId = process.process.getPayload();
|
||||
if (!dataFileId) {
|
||||
return;
|
||||
}
|
||||
return `/dbeaver/data/${dataFileId}`;
|
||||
}
|
||||
|
||||
async exportData(
|
||||
context: IExportContext,
|
||||
parameters: DataTransferParameters
|
||||
): Promise<string> {
|
||||
let process: Process;
|
||||
if (context.containerNodePath) {
|
||||
process = await this.exportFromContainer(context.connectionId, context.containerNodePath, parameters);
|
||||
} else {
|
||||
process = await this.exportFromResults(context.connectionId, context.contextId!, context.resultId!, parameters);
|
||||
}
|
||||
|
||||
this.exportProcesses.addValue({
|
||||
...process,
|
||||
context,
|
||||
parameters,
|
||||
});
|
||||
|
||||
return process.taskId;
|
||||
}
|
||||
|
||||
private async exportFromContainer(
|
||||
connectionId: string,
|
||||
containerNodePath: string,
|
||||
parameters: DataTransferParameters
|
||||
): Promise<Process> {
|
||||
const process = new ExportFromContainerProcess(this.graphQLService, this.notificationService);
|
||||
const taskId = await process.start(connectionId, containerNodePath, parameters);
|
||||
return { taskId, process };
|
||||
}
|
||||
|
||||
private async exportFromResults(
|
||||
connectionId: string,
|
||||
contextId: string,
|
||||
resultsId: string,
|
||||
parameters: DataTransferParameters
|
||||
): Promise<Process> {
|
||||
const process = new ExportFromResultsProcess(this.graphQLService, this.notificationService);
|
||||
const taskId = await process.start(connectionId, contextId, resultsId, parameters);
|
||||
|
||||
return { taskId, process };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { NotificationService } from '@cloudbeaver/core-events';
|
||||
import {
|
||||
CachedResource, GraphQLService, DataTransferProcessorInfo, DataTransferParameters
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { DataExportProcessService } from './DataExportProcessService';
|
||||
import { ExportNotification } from './ExportNotification/ExportNotification';
|
||||
import { IExportContext } from './IExportContext';
|
||||
|
||||
type ProcessorsResourceMetadata = {
|
||||
loaded: boolean;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class DataExportService {
|
||||
readonly processors = new CachedResource(
|
||||
new Map(),
|
||||
this.refreshProcessorsAsync.bind(this),
|
||||
(_, { loaded }) => loaded
|
||||
);
|
||||
|
||||
constructor(
|
||||
private graphQLService: GraphQLService,
|
||||
private notificationService: NotificationService,
|
||||
private dataExportProcessService: DataExportProcessService,
|
||||
) { }
|
||||
|
||||
async cancel(exportId: string) {
|
||||
await this.dataExportProcessService.cancel(exportId);
|
||||
}
|
||||
|
||||
async delete(exportId: string) {
|
||||
await this.dataExportProcessService.delete(exportId);
|
||||
}
|
||||
|
||||
download(exportId: string) {
|
||||
this.dataExportProcessService.download(exportId);
|
||||
}
|
||||
|
||||
downloadUrl(exportId: string) {
|
||||
return this.dataExportProcessService.download(exportId);
|
||||
}
|
||||
|
||||
async exportData(
|
||||
context: IExportContext,
|
||||
parameters: DataTransferParameters
|
||||
) {
|
||||
const taskId = await this.dataExportProcessService.exportData(
|
||||
context,
|
||||
parameters
|
||||
);
|
||||
|
||||
this.notificationService.customNotification(() => ExportNotification, taskId);
|
||||
return taskId;
|
||||
}
|
||||
|
||||
private async refreshProcessorsAsync(
|
||||
data: Map<string, DataTransferProcessorInfo>,
|
||||
metadata: ProcessorsResourceMetadata,
|
||||
): Promise<Map<string, DataTransferProcessorInfo>> {
|
||||
const { processors } = await this.graphQLService.gql.getDataTransferProcessors();
|
||||
|
||||
data.clear();
|
||||
|
||||
for (const processor of processors) {
|
||||
data.set(processor.id, processor);
|
||||
}
|
||||
metadata.loaded = true;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observable, computed } from 'mobx';
|
||||
|
||||
import { ErrorDetailsDialog } from '@cloudbeaver/core-app';
|
||||
import { IProperty } from '@cloudbeaver/core-blocks';
|
||||
import { injectable, IInitializableController, IDestructibleController } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { DataTransferProcessorInfo, GQLErrorCatcher } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { DataExportService } from '../DataExportService';
|
||||
import { IExportContext } from '../IExportContext';
|
||||
|
||||
export enum DataExportStep {
|
||||
DataTransferProcessor,
|
||||
Configure
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class DataExportController implements IInitializableController, IDestructibleController {
|
||||
@observable step = DataExportStep.DataTransferProcessor
|
||||
get isLoading() {
|
||||
return this.dataExportService.processors.isLoading();
|
||||
}
|
||||
@observable isExporting = false
|
||||
@observable processor: DataTransferProcessorInfo | null = null
|
||||
|
||||
@computed get processors(): DataTransferProcessorInfo[] {
|
||||
return Array
|
||||
.from(
|
||||
this.dataExportService.processors.data.values()
|
||||
)
|
||||
.sort(sortProcessors);
|
||||
}
|
||||
|
||||
@observable processorProperties: any = {}
|
||||
@observable properties: IProperty[] = []
|
||||
|
||||
readonly error = new GQLErrorCatcher();
|
||||
|
||||
private context!: IExportContext;
|
||||
private close!: () => void;
|
||||
private isDistructed = false;
|
||||
|
||||
constructor(
|
||||
private dataExportService: DataExportService,
|
||||
private notificationService: NotificationService,
|
||||
private commonDialogService: CommonDialogService
|
||||
) { }
|
||||
|
||||
init(context: IExportContext, close: () => void) {
|
||||
this.context = context;
|
||||
this.close = close;
|
||||
this.loadProcessors();
|
||||
}
|
||||
|
||||
destruct(): void {
|
||||
this.isDistructed = true;
|
||||
}
|
||||
|
||||
prepareExport = async () => {
|
||||
if (!this.processor || this.isExporting) {
|
||||
return;
|
||||
}
|
||||
this.isExporting = true;
|
||||
|
||||
try {
|
||||
await this.dataExportService.exportData(
|
||||
this.context,
|
||||
{
|
||||
processorId: this.processor.id,
|
||||
processorProperties: this.processorProperties,
|
||||
}
|
||||
);
|
||||
this.close();
|
||||
} catch (exception) {
|
||||
if (!this.error.catch(exception) || this.isDistructed) {
|
||||
this.notificationService.logException(exception, 'Can\'t export');
|
||||
}
|
||||
} finally {
|
||||
this.isExporting = false;
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
setStep = (step: DataExportStep) => {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
selectProcessor = (processorId: string) => {
|
||||
this.processor = this.dataExportService
|
||||
.processors
|
||||
.data
|
||||
.get(processorId)!;
|
||||
|
||||
this.properties = this.processor.properties?.map(property => ({
|
||||
id: property.id!,
|
||||
key: property.id!,
|
||||
displayName: property.displayName!,
|
||||
description: property.description,
|
||||
validValues: property.validValues,
|
||||
defaultValue: property.defaultValue,
|
||||
})) || [];
|
||||
|
||||
this.processorProperties = {};
|
||||
|
||||
this.step = DataExportStep.Configure;
|
||||
this.error.clear();
|
||||
}
|
||||
|
||||
showDetails = () => {
|
||||
if (this.error.exception) {
|
||||
this.commonDialogService.open(ErrorDetailsDialog, this.error.exception);
|
||||
}
|
||||
}
|
||||
|
||||
private async loadProcessors() {
|
||||
try {
|
||||
await this.dataExportService.processors.load();
|
||||
} catch (exception) {
|
||||
this.notificationService.logException(exception, 'Can\'t load data export processors');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sortProcessors(processorA: DataTransferProcessorInfo, processorB: DataTransferProcessorInfo): number {
|
||||
if (processorA.order === processorB.order)
|
||||
{
|
||||
return (processorA.name || '').localeCompare((processorB.name || ''));
|
||||
}
|
||||
|
||||
return processorA.order - processorB.order;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
|
||||
import { useController } from '@cloudbeaver/core-di';
|
||||
import { DialogComponentProps } from '@cloudbeaver/core-dialogs';
|
||||
|
||||
import { IExportContext } from '../IExportContext';
|
||||
import { DataExportController, DataExportStep } from './DataExportController';
|
||||
import { ProcessorConfigureDialog } from './ProcessorConfigureDialog';
|
||||
import { ProcessorSelectDialog } from './ProcessorSelectDialog';
|
||||
|
||||
export const DataExportDialog = observer(function DataExportDialog({
|
||||
payload,
|
||||
rejectDialog,
|
||||
}: DialogComponentProps<IExportContext, null>) {
|
||||
const controller = useController(DataExportController, payload, rejectDialog);
|
||||
|
||||
if (controller.step === DataExportStep.Configure && controller.processor) {
|
||||
return (
|
||||
<ProcessorConfigureDialog
|
||||
processor={controller.processor}
|
||||
properties={controller.properties}
|
||||
processorProperties={controller.processorProperties}
|
||||
error={controller.error}
|
||||
isExporting={controller.isExporting}
|
||||
onShowDetails={controller.showDetails}
|
||||
onBack={() => controller.setStep(DataExportStep.DataTransferProcessor)}
|
||||
onClose={rejectDialog}
|
||||
onExport={controller.prepareExport}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ProcessorSelectDialog
|
||||
context={payload}
|
||||
processors={controller.processors}
|
||||
onSelect={controller.selectProcessor}
|
||||
isLoading={controller.isLoading}
|
||||
onClose={rejectDialog}
|
||||
/>
|
||||
);
|
||||
});
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
|
||||
import { ItemList } from '@cloudbeaver/core-blocks';
|
||||
import { DataTransferProcessorInfo } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { ProcessorItem } from './ProcessorItem';
|
||||
|
||||
type ExportProcessorListProps = {
|
||||
processors: DataTransferProcessorInfo[];
|
||||
onSelect(processorId: string): void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ExportProcessorList = observer(function ExportProcessorList({
|
||||
processors,
|
||||
onSelect,
|
||||
className,
|
||||
}: ExportProcessorListProps) {
|
||||
|
||||
return (
|
||||
<ItemList className={className}>
|
||||
{processors.map(processor => <ProcessorItem key={processor.id} processor={processor} onSelect={onSelect}/>)}
|
||||
</ItemList>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { ListItem } from '@cloudbeaver/core-blocks';
|
||||
import { DataTransferProcessorInfo } from '@cloudbeaver/core-sdk';
|
||||
|
||||
type ProcessorItemProps = {
|
||||
processor: DataTransferProcessorInfo;
|
||||
onSelect(processorId: string): void;
|
||||
}
|
||||
|
||||
export const ProcessorItem = observer(function ProcessorItem({
|
||||
processor,
|
||||
onSelect,
|
||||
}: ProcessorItemProps) {
|
||||
const select = useCallback(() => onSelect(processor.id), [processor]);
|
||||
return <ListItem icon={processor.icon} name={processor.name} description={processor.description} onClick={select}/>;
|
||||
});
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { IProperty, PropertiesTable, ErrorMessage } from '@cloudbeaver/core-blocks';
|
||||
import { CommonDialogWrapper } from '@cloudbeaver/core-dialogs';
|
||||
import { useTranslate } from '@cloudbeaver/core-localization';
|
||||
import { DataTransferProcessorInfo, GQLErrorCatcher } from '@cloudbeaver/core-sdk';
|
||||
import { composes, useStyles } from '@cloudbeaver/core-theming';
|
||||
|
||||
import { ProcessorConfigureDialogFooter } from './ProcessorConfigureDialogFooter';
|
||||
|
||||
const styles = composes(
|
||||
css`
|
||||
Tab {
|
||||
composes: theme-ripple theme-background-secondary theme-text-on-secondary from global;
|
||||
}
|
||||
ErrorMessage {
|
||||
composes: theme-background-secondary from global;
|
||||
}
|
||||
`,
|
||||
css`
|
||||
CommonDialogWrapper {
|
||||
max-height: 500px;
|
||||
min-height: 500px;
|
||||
}
|
||||
PropertiesTable {
|
||||
flex: 1;
|
||||
}
|
||||
message {
|
||||
margin: auto;
|
||||
}
|
||||
ErrorMessage {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
padding: 8px 24px;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
type ProcessorSelectDialogProps = {
|
||||
processor: DataTransferProcessorInfo;
|
||||
properties: IProperty[];
|
||||
processorProperties: any;
|
||||
error: GQLErrorCatcher;
|
||||
isExporting: boolean;
|
||||
onShowDetails(): void;
|
||||
onClose(): void;
|
||||
onBack(): void;
|
||||
onExport(): void;
|
||||
}
|
||||
|
||||
export const ProcessorConfigureDialog = observer(
|
||||
function ProcessorConfigureDialog({
|
||||
processor,
|
||||
properties,
|
||||
processorProperties,
|
||||
error,
|
||||
isExporting,
|
||||
onShowDetails,
|
||||
onClose,
|
||||
onBack,
|
||||
onExport,
|
||||
}: ProcessorSelectDialogProps) {
|
||||
const translate = useTranslate();
|
||||
const title = `${translate('data_transfer_dialog_configuration_title')} (${processor.name})`;
|
||||
|
||||
return styled(useStyles(styles))(
|
||||
<CommonDialogWrapper
|
||||
title={title}
|
||||
noBodyPadding
|
||||
footer={
|
||||
<ProcessorConfigureDialogFooter
|
||||
isExporting={isExporting}
|
||||
onExport={onExport}
|
||||
onBack={onBack}
|
||||
onCancel={onClose}
|
||||
/>
|
||||
}
|
||||
onReject={onClose}
|
||||
>
|
||||
<PropertiesTable
|
||||
properties={properties}
|
||||
propertiesState={processorProperties}
|
||||
/>
|
||||
{error.responseMessage && (
|
||||
<ErrorMessage
|
||||
text={error.responseMessage}
|
||||
hasDetails={error.hasDetails}
|
||||
onShowDetails={onShowDetails}
|
||||
/>
|
||||
)}
|
||||
</CommonDialogWrapper>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { Button } from '@cloudbeaver/core-blocks';
|
||||
import { useTranslate } from '@cloudbeaver/core-localization';
|
||||
|
||||
const styles = css`
|
||||
controls {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
fill {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
Button:not(:first-child) {
|
||||
margin-left: 24px;
|
||||
}
|
||||
`;
|
||||
|
||||
type Props = {
|
||||
isExporting: boolean;
|
||||
onCancel(): void;
|
||||
onExport(): void;
|
||||
onBack(): void;
|
||||
}
|
||||
|
||||
export const ProcessorConfigureDialogFooter = observer(
|
||||
function ProcessorConfigureDialogFooter({
|
||||
isExporting,
|
||||
onCancel,
|
||||
onExport,
|
||||
onBack,
|
||||
}: Props) {
|
||||
const translate = useTranslate();
|
||||
|
||||
return styled(styles)(
|
||||
<controls as="div">
|
||||
<Button
|
||||
type="button"
|
||||
mod={['outlined']}
|
||||
onClick={onBack}
|
||||
disabled={isExporting}
|
||||
>
|
||||
{translate('ui_stepper_back')}
|
||||
</Button>
|
||||
<fill as="div"/>
|
||||
<Button
|
||||
type="button"
|
||||
mod={['outlined']}
|
||||
onClick={onCancel}
|
||||
disabled={isExporting}
|
||||
>
|
||||
{translate('ui_processing_cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
mod={['unelevated']}
|
||||
onClick={onExport}
|
||||
disabled={isExporting}
|
||||
>
|
||||
{translate('data_transfer_dialog_export')}
|
||||
</Button>
|
||||
</controls>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import styled, { css } from 'reshadow';
|
||||
|
||||
import { useNode } from '@cloudbeaver/core-app';
|
||||
import { Loader } from '@cloudbeaver/core-blocks';
|
||||
import { CommonDialogWrapper } from '@cloudbeaver/core-dialogs';
|
||||
import { useTranslate } from '@cloudbeaver/core-localization';
|
||||
import { DataTransferProcessorInfo } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { IExportContext } from '../IExportContext';
|
||||
import { ExportProcessorList } from './ExportProcessorList/ExportProcessorList';
|
||||
|
||||
const styles = css`
|
||||
CommonDialogWrapper {
|
||||
max-height: 500px;
|
||||
min-height: 500px;
|
||||
}
|
||||
ExportProcessorList {
|
||||
flex: 1;
|
||||
}
|
||||
export-object {
|
||||
composes: theme-typography--body2 from global;
|
||||
flex-shrink: 0;
|
||||
padding: 16px;
|
||||
max-height: 50px;
|
||||
overflow: hidden;
|
||||
|
||||
& pre {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
type ProcessorSelectDialogProps = {
|
||||
context: IExportContext;
|
||||
processors: DataTransferProcessorInfo[];
|
||||
isLoading: boolean;
|
||||
onSelect(processorId: string): void;
|
||||
onClose(): void;
|
||||
}
|
||||
|
||||
export const ProcessorSelectDialog = observer(
|
||||
function ProcessorSelectDialog({
|
||||
context,
|
||||
processors,
|
||||
isLoading,
|
||||
onSelect,
|
||||
onClose,
|
||||
}: ProcessorSelectDialogProps) {
|
||||
const translate = useTranslate();
|
||||
const { node } = useNode(context.containerNodePath || '');
|
||||
|
||||
return styled(styles)(
|
||||
<CommonDialogWrapper
|
||||
title={translate('data_transfer_dialog_title')}
|
||||
noBodyPadding
|
||||
onReject={onClose}
|
||||
>
|
||||
<export-object as="div">
|
||||
{context.sourceName ? translate('data_transfer_exporting_sql') : `${translate('data_transfer_exporting_table')} ${node?.name}`}
|
||||
<pre title={context.sourceName}>{context.sourceName}</pre>
|
||||
</export-object>
|
||||
{isLoading && <Loader />}
|
||||
{!isLoading && <ExportProcessorList processors={processors} onSelect={onSelect}/>}
|
||||
</CommonDialogWrapper>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { NotificationService } from '@cloudbeaver/core-events';
|
||||
import {
|
||||
AsyncTaskInfo, GraphQLService, ServerInternalError, DataTransferParameters,
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
import {
|
||||
CancellablePromise, cancellableTimeout, Deferred, EDeferredState,
|
||||
} from '@cloudbeaver/core-utils';
|
||||
|
||||
const DELAY_BETWEEN_TRIES = 1000;
|
||||
|
||||
// TODO: seems we need special abstraction over async tasks to manage it
|
||||
export class ExportFromContainerProcess extends Deferred<string> {
|
||||
|
||||
private taskId?: string;
|
||||
private timeout?: CancellablePromise<void>;
|
||||
private isCancelConfirmed = false; // true when server successfully executed cancelQueryAsync
|
||||
|
||||
constructor(private graphQLService: GraphQLService,
|
||||
private notificationService: NotificationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
async start(
|
||||
connectionId: string,
|
||||
containerNodePath: string,
|
||||
parameters: DataTransferParameters
|
||||
): Promise<string> {
|
||||
// start async task
|
||||
try {
|
||||
const { taskInfo } = await this.graphQLService.gql.exportDataFromContainer({
|
||||
connectionId,
|
||||
containerNodePath,
|
||||
parameters,
|
||||
});
|
||||
this.applyResult(taskInfo);
|
||||
this.taskId = taskInfo.id;
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
await this.cancelAsync(this.taskId);
|
||||
}
|
||||
|
||||
this.statusUpdateProcess();
|
||||
|
||||
return this.taskId;
|
||||
} catch (e) {
|
||||
this.onError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method just mark process as cancelling
|
||||
* to avoid racing conditions the server request will be executed in synchronous manner in start method
|
||||
*/
|
||||
cancel() {
|
||||
if (this.getState() !== EDeferredState.PENDING) {
|
||||
return;
|
||||
}
|
||||
this.toCancelling();
|
||||
if (this.timeout) {
|
||||
this.timeout.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private async statusUpdateProcess() {
|
||||
if (this.isFinished || !this.taskId) {
|
||||
return;
|
||||
}
|
||||
// check async task status until execution finished
|
||||
while (this.isInProgress) {
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
await this.cancelAsync(this.taskId);
|
||||
}
|
||||
// run the first check immediately because usually the query execution is fast
|
||||
try {
|
||||
const { taskInfo } = await this.graphQLService.gql.asyncExportTaskStatus({ taskId: this.taskId });
|
||||
this.applyResult(taskInfo);
|
||||
if (this.isFinished) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
this.notificationService.logException(e, 'Failed to check async task status');
|
||||
}
|
||||
|
||||
try {
|
||||
this.timeout = cancellableTimeout(DELAY_BETWEEN_TRIES);
|
||||
await this.timeout;
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private async cancelAsync(taskId: string) {
|
||||
if (this.isCancelConfirmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.graphQLService.gql.asyncTaskCancel({ taskId });
|
||||
this.isCancelConfirmed = true;
|
||||
} catch (e) {
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
this.toPending();
|
||||
this.notificationService.logException(e, 'Failed to cancel async task');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private applyResult(taskInfo: AsyncTaskInfo): void {
|
||||
// task is running
|
||||
if (taskInfo.running) {
|
||||
return;
|
||||
}
|
||||
// task failed to execute
|
||||
if (taskInfo.error) {
|
||||
const serverError = new ServerInternalError(taskInfo.error);
|
||||
this.onError(serverError, taskInfo.status);
|
||||
return;
|
||||
}
|
||||
if (!taskInfo.taskResult) {
|
||||
this.onError(new Error('Tasks execution returns no taskResult'), taskInfo.status);
|
||||
return;
|
||||
}
|
||||
// task execution successful
|
||||
this.toResolved(taskInfo.taskResult);
|
||||
}
|
||||
|
||||
private onError(error: Error, status?: string) {
|
||||
// if task failed to execute during cancelling - it means it was cancelled successfully
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
this.toCancelled(error);
|
||||
} else {
|
||||
this.toRejected(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { NotificationService } from '@cloudbeaver/core-events';
|
||||
import {
|
||||
AsyncTaskInfo, GraphQLService, ServerInternalError, DataTransferParameters,
|
||||
} from '@cloudbeaver/core-sdk';
|
||||
import {
|
||||
CancellablePromise, cancellableTimeout, Deferred, EDeferredState,
|
||||
} from '@cloudbeaver/core-utils';
|
||||
|
||||
const DELAY_BETWEEN_TRIES = 1000;
|
||||
|
||||
// TODO: seems we need special abstraction over async tasks to manage it
|
||||
export class ExportFromResultsProcess extends Deferred<string> {
|
||||
|
||||
private taskId?: string;
|
||||
private timeout?: CancellablePromise<void>;
|
||||
private isCancelConfirmed = false; // true when server successfully executed cancelQueryAsync
|
||||
|
||||
constructor(private graphQLService: GraphQLService,
|
||||
private notificationService: NotificationService) {
|
||||
super();
|
||||
}
|
||||
|
||||
async start(
|
||||
connectionId: string,
|
||||
contextId: string,
|
||||
resultsId: string,
|
||||
parameters: DataTransferParameters
|
||||
): Promise<string> {
|
||||
// start async task
|
||||
try {
|
||||
const { taskInfo } = await this.graphQLService.gql.exportDataFromResults({
|
||||
connectionId,
|
||||
contextId,
|
||||
resultsId,
|
||||
parameters,
|
||||
});
|
||||
this.applyResult(taskInfo);
|
||||
this.taskId = taskInfo.id;
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
await this.cancelAsync(this.taskId);
|
||||
}
|
||||
|
||||
this.statusUpdateProcess();
|
||||
|
||||
return this.taskId;
|
||||
} catch (e) {
|
||||
this.onError(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* this method just mark process as cancelling
|
||||
* to avoid racing conditions the server request will be executed in synchronous manner in start method
|
||||
*/
|
||||
cancel() {
|
||||
if (this.getState() !== EDeferredState.PENDING) {
|
||||
return;
|
||||
}
|
||||
this.toCancelling();
|
||||
if (this.timeout) {
|
||||
this.timeout.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private async statusUpdateProcess() {
|
||||
if (this.isFinished || !this.taskId) {
|
||||
return;
|
||||
}
|
||||
// check async task status until execution finished
|
||||
while (this.isInProgress) {
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
await this.cancelAsync(this.taskId);
|
||||
}
|
||||
// run the first check immediately because usually the query execution is fast
|
||||
try {
|
||||
const { taskInfo } = await this.graphQLService.gql.asyncExportTaskStatus({ taskId: this.taskId });
|
||||
this.applyResult(taskInfo);
|
||||
if (this.isFinished) {
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
this.notificationService.logException(e, 'Failed to check async task status');
|
||||
}
|
||||
|
||||
try {
|
||||
this.timeout = cancellableTimeout(DELAY_BETWEEN_TRIES);
|
||||
await this.timeout;
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private async cancelAsync(taskId: string) {
|
||||
if (this.isCancelConfirmed) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.graphQLService.gql.asyncTaskCancel({ taskId });
|
||||
this.isCancelConfirmed = true;
|
||||
} catch (e) {
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
this.toPending();
|
||||
this.notificationService.logException(e, 'Failed to cancel async task');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private applyResult(taskInfo: AsyncTaskInfo): void {
|
||||
// task is running
|
||||
if (taskInfo.running) {
|
||||
return;
|
||||
}
|
||||
// task failed to execute
|
||||
if (taskInfo.error) {
|
||||
const serverError = new ServerInternalError(taskInfo.error);
|
||||
this.onError(serverError, taskInfo.status);
|
||||
return;
|
||||
}
|
||||
if (!taskInfo.taskResult) {
|
||||
this.onError(new Error('Tasks execution returns no taskResult'), taskInfo.status);
|
||||
return;
|
||||
}
|
||||
// task execution successful
|
||||
this.toResolved(taskInfo.taskResult);
|
||||
}
|
||||
|
||||
private onError(error: Error, status?: string) {
|
||||
// if task failed to execute during cancelling - it means it was cancelled successfully
|
||||
if (this.getState() === EDeferredState.CANCELLING) {
|
||||
this.toCancelled(error);
|
||||
} else {
|
||||
this.toRejected(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observer } from 'mobx-react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import styled, { use, css } from 'reshadow';
|
||||
|
||||
import { SNACKBAR_STYLES } from '@cloudbeaver/core-app';
|
||||
import { Button, Loader, IconButton } from '@cloudbeaver/core-blocks';
|
||||
import { useController } from '@cloudbeaver/core-di';
|
||||
import { NotificationComponentProps } from '@cloudbeaver/core-events';
|
||||
import { useTranslate } from '@cloudbeaver/core-localization';
|
||||
import { useStyles } from '@cloudbeaver/core-theming';
|
||||
import { EDeferredState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { ExportNotificationController } from './ExportNotificationController';
|
||||
|
||||
const styles = css`
|
||||
Loader {
|
||||
margin-right: 16px;
|
||||
}
|
||||
source-name {
|
||||
composes: theme-typography--body2 from global;
|
||||
padding-top: 16px;
|
||||
max-height: 50px;
|
||||
overflow: hidden;
|
||||
|
||||
& pre {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
IconButton {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
}
|
||||
`;
|
||||
|
||||
export const ExportNotification = observer(function ExportNotification({
|
||||
notification,
|
||||
}: NotificationComponentProps<string>) {
|
||||
const controller = useController(ExportNotificationController, notification);
|
||||
const translate = useTranslate();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
return styled(useStyles(SNACKBAR_STYLES, styles))(
|
||||
<notification as="div" {...use({ mounted })} >
|
||||
<notification-header as="div">
|
||||
<Loader loading={controller.isPending} hideMessage />
|
||||
<message as="div">{translate(controller.status)}</message>
|
||||
{!controller.isPending && (
|
||||
<IconButton onClick={controller.delete} name="cross" viewBox="0 0 16 16" />
|
||||
)}
|
||||
</notification-header>
|
||||
<notification-body as="div">
|
||||
<source-name as="div">
|
||||
{controller.sourceName}
|
||||
<pre title={controller.task?.context.sourceName}>{controller.task?.context.sourceName}</pre>
|
||||
</source-name>
|
||||
<actions as="div">
|
||||
{controller.isSuccess && (
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
mod={['outlined']}
|
||||
onClick={controller.delete}
|
||||
>
|
||||
{translate('data_transfer_notification_delete')}
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
tag='a'
|
||||
href={controller.downloadUrl}
|
||||
mod={['unelevated']}
|
||||
onClick={controller.download}
|
||||
download
|
||||
>
|
||||
{translate('data_transfer_notification_download')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
{controller.hasDetails && (
|
||||
<Button
|
||||
type="button"
|
||||
mod={['outlined']}
|
||||
onClick={controller.showDetails}
|
||||
disabled={controller.isDetailsDialogOpen}
|
||||
>
|
||||
{translate('ui_errors_details')}
|
||||
</Button>
|
||||
)}
|
||||
{controller.isPending && (
|
||||
<Button
|
||||
type="button"
|
||||
mod={['outlined']}
|
||||
onClick={controller.cancel}
|
||||
disabled={controller.process?.getState() === EDeferredState.CANCELLING}
|
||||
>
|
||||
{translate('ui_processing_cancel')}
|
||||
</Button>
|
||||
)}
|
||||
</actions>
|
||||
</notification-body>
|
||||
</notification>
|
||||
);
|
||||
});
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { observable, computed } from 'mobx';
|
||||
|
||||
import { ErrorDetailsDialog, NavNodeManagerService } from '@cloudbeaver/core-app';
|
||||
import { IInitializableController, injectable } from '@cloudbeaver/core-di';
|
||||
import { CommonDialogService } from '@cloudbeaver/core-dialogs';
|
||||
import { INotification } from '@cloudbeaver/core-events';
|
||||
import { LocalizationService } from '@cloudbeaver/core-localization';
|
||||
import { EDeferredState } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { DataExportProcessService } from '../DataExportProcessService';
|
||||
|
||||
@injectable()
|
||||
export class ExportNotificationController implements IInitializableController {
|
||||
@observable isDetailsDialogOpen = false;
|
||||
|
||||
get isSuccess() {
|
||||
return this.process?.getState() === EDeferredState.RESOLVED;
|
||||
}
|
||||
|
||||
get isPending() {
|
||||
return this.process?.isInProgress;
|
||||
}
|
||||
|
||||
get process() {
|
||||
return this.task?.process;
|
||||
}
|
||||
|
||||
get task() {
|
||||
return this.dataExportProcessService.exportProcesses.get(this.notification.source);
|
||||
}
|
||||
|
||||
get hasDetails() {
|
||||
return !!this.process?.getRejectionReason();
|
||||
}
|
||||
|
||||
@computed get sourceName() {
|
||||
if (!this.task) {
|
||||
return '';
|
||||
}
|
||||
if (this.task.context.containerNodePath) {
|
||||
const node = this.navNodeManagerService.getNode(this.task.context.containerNodePath);
|
||||
|
||||
return `${this.localization.translate('data_transfer_exporting_table')} ${node?.name}`;
|
||||
}
|
||||
|
||||
return this.localization.translate('data_transfer_exporting_sql');
|
||||
}
|
||||
|
||||
get status() {
|
||||
switch (this.process?.getState()) {
|
||||
case EDeferredState.PENDING:
|
||||
return 'data_transfer_notification_preparation';
|
||||
case EDeferredState.CANCELLING:
|
||||
return 'ui_processing_canceling';
|
||||
case EDeferredState.RESOLVED:
|
||||
return 'data_transfer_notification_ready';
|
||||
default:
|
||||
return 'data_transfer_notification_error';
|
||||
}
|
||||
}
|
||||
|
||||
get downloadUrl() {
|
||||
return this.dataExportProcessService.downloadUrl(this.notification.source);
|
||||
}
|
||||
|
||||
private notification!: INotification<any>;
|
||||
|
||||
constructor(
|
||||
private commonDialogService: CommonDialogService,
|
||||
private dataExportProcessService: DataExportProcessService,
|
||||
private navNodeManagerService: NavNodeManagerService,
|
||||
private localization: LocalizationService,
|
||||
) {}
|
||||
|
||||
init(notification: INotification<any>) {
|
||||
this.notification = notification;
|
||||
}
|
||||
|
||||
delete = () => {
|
||||
this.dataExportProcessService.delete(this.notification.source);
|
||||
this.notification.close();
|
||||
}
|
||||
|
||||
download = () => {
|
||||
this.dataExportProcessService.download(this.notification.source);
|
||||
this.notification.close();
|
||||
}
|
||||
|
||||
cancel = () => {
|
||||
this.dataExportProcessService.cancel(this.notification.source);
|
||||
}
|
||||
|
||||
showDetails= async () => {
|
||||
this.isDetailsDialogOpen = true;
|
||||
try {
|
||||
this.notification.showDetails();
|
||||
await this.commonDialogService.open(ErrorDetailsDialog, this.process?.getRejectionReason());
|
||||
} finally {
|
||||
this.isDetailsDialogOpen = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
export interface IExportContext {
|
||||
connectionId: string;
|
||||
contextId?: string;
|
||||
containerNodePath?: string;
|
||||
resultId?: string | null;
|
||||
sourceName?: string;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { manifest } from './manifest';
|
||||
|
||||
export default manifest;
|
||||
|
||||
export * from './DataExportMenuService';
|
||||
export * from './DataExportService';
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* cloudbeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020 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 { IServiceInjector, PluginManifest } from '@cloudbeaver/core-di';
|
||||
|
||||
import { Bootstrap } from './Bootstrap';
|
||||
import { DataExportMenuService } from './DataExportMenuService';
|
||||
import { DataExportProcessService } from './DataExportProcessService';
|
||||
import { DataExportService } from './DataExportService';
|
||||
|
||||
export const manifest: PluginManifest = {
|
||||
info: {
|
||||
name: 'Data Export Plugin',
|
||||
},
|
||||
|
||||
providers: [
|
||||
DataExportMenuService,
|
||||
DataExportService,
|
||||
DataExportProcessService,
|
||||
],
|
||||
|
||||
async initialize(services: IServiceInjector) {
|
||||
services
|
||||
.resolveServiceByClass(Bootstrap)
|
||||
.bootstrap();
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib"
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
Reference in New Issue
Block a user