mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
feat(plugin-data-viewer): CB-751 database data actions API & select action
This commit is contained in:
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2021 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 type { IDatabaseDataActionClass } from '../IDatabaseDataAction';
|
||||
|
||||
export function databaseDataAction<T extends IDatabaseDataActionClass<any, any>>() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
||||
return <U extends T>(constructor: U) => { };
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2021 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 type { IExecutor } from '@cloudbeaver/core-executor';
|
||||
|
||||
import type { IDatabaseDataAction } from '../IDatabaseDataAction';
|
||||
import type { IDatabaseDataResult } from '../IDatabaseDataResult';
|
||||
|
||||
export type DatabaseDataEditorActionsData<TKey> = {
|
||||
type: 'select';
|
||||
resultId: string;
|
||||
key: TKey;
|
||||
selected: boolean;
|
||||
} | {
|
||||
type: 'clear';
|
||||
resultId: string;
|
||||
};
|
||||
|
||||
export interface IDatabaseDataSelectAction<TKey, TResult extends IDatabaseDataResult>
|
||||
extends IDatabaseDataAction<TResult> {
|
||||
readonly actions: IExecutor<DatabaseDataEditorActionsData<TKey>>;
|
||||
isSelected: () => boolean;
|
||||
isElementSelected: (key: TKey) => boolean;
|
||||
set: (key: TKey, selected: boolean) => void;
|
||||
clear: () => void;
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2021 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 { Executor, IExecutor } from '@cloudbeaver/core-executor';
|
||||
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import type { IDatabaseResultSet } from '../IDatabaseResultSet';
|
||||
import { databaseDataAction } from './DatabaseDataActionDecorator';
|
||||
import type { DatabaseDataEditorActionsData, IDatabaseDataSelectAction } from './IDatabaseDataSelectAction';
|
||||
|
||||
export interface IResultSetSelectKey {
|
||||
row: number;
|
||||
column?: number;
|
||||
}
|
||||
|
||||
@databaseDataAction()
|
||||
export class ResultSetSelectAction implements IDatabaseDataSelectAction<IResultSetSelectKey, IDatabaseResultSet> {
|
||||
static dataFormat = ResultDataFormat.Resultset;
|
||||
|
||||
result: IDatabaseResultSet;
|
||||
|
||||
readonly actions: IExecutor<DatabaseDataEditorActionsData<IResultSetSelectKey>>;
|
||||
private selectedElements: Map<number, number[]>;
|
||||
|
||||
constructor(result: IDatabaseResultSet) {
|
||||
this.result = result;
|
||||
this.actions = new Executor();
|
||||
this.selectedElements = new Map();
|
||||
}
|
||||
|
||||
updateResult(result: IDatabaseResultSet): void {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
isSelected(): boolean {
|
||||
return this.selectedElements.size > 0;
|
||||
}
|
||||
|
||||
isElementSelected(key: IResultSetSelectKey): boolean {
|
||||
const row = this.selectedElements.get(key.row);
|
||||
|
||||
if (!row) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (key.column !== undefined) {
|
||||
return row.includes(key.column);
|
||||
}
|
||||
|
||||
return row.length === this.result.data?.columns?.length;
|
||||
}
|
||||
|
||||
set(key: IResultSetSelectKey, selected: boolean): void {
|
||||
try {
|
||||
if (!this.selectedElements.has(key.row)) {
|
||||
if (!selected) {
|
||||
return;
|
||||
}
|
||||
this.selectedElements.set(key.row, []);
|
||||
}
|
||||
|
||||
const columns = this.selectedElements.get(key.row)!;
|
||||
|
||||
if (key.column) {
|
||||
if (selected) {
|
||||
if (!columns.includes(key.column)) {
|
||||
columns.push(key.column);
|
||||
}
|
||||
} else {
|
||||
const index = columns.indexOf(key.column);
|
||||
|
||||
if (index >= 0) {
|
||||
columns.splice(index, 1);
|
||||
}
|
||||
|
||||
if (columns.length === 0) {
|
||||
this.selectedElements.delete(key.row);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
columns.push(...(this.result.data?.columns?.map((c, i) => i) || []));
|
||||
} else {
|
||||
this.selectedElements.delete(key.row);
|
||||
}
|
||||
} finally {
|
||||
this.actions.execute({
|
||||
type: 'select',
|
||||
resultId: this.result.id,
|
||||
key,
|
||||
selected,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.actions.execute({
|
||||
type: 'clear',
|
||||
resultId: this.result.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2021 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 { makeObservable, observable } from 'mobx';
|
||||
|
||||
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
|
||||
import type { IDatabaseDataActions } from './IDatabaseDataActions';
|
||||
import type { IDatabaseDataResult } from './IDatabaseDataResult';
|
||||
|
||||
type ActionsMap<TResult extends IDatabaseDataResult> = Map<
|
||||
IDatabaseDataActionClass<TResult, IDatabaseDataAction<TResult>>,
|
||||
IDatabaseDataAction<TResult>
|
||||
>;
|
||||
|
||||
export class DatabaseDataActions<TResult extends IDatabaseDataResult> implements IDatabaseDataActions<TResult> {
|
||||
private actions: Map<string, ActionsMap<TResult>>;
|
||||
|
||||
constructor() {
|
||||
this.actions = new Map();
|
||||
|
||||
makeObservable<DatabaseDataActions<TResult>, 'actions'>(this, {
|
||||
actions: observable.shallow,
|
||||
});
|
||||
}
|
||||
|
||||
get <T extends IDatabaseDataAction<TResult>>(
|
||||
result: TResult,
|
||||
Action: IDatabaseDataActionClass<TResult, T>
|
||||
): T {
|
||||
if (!this.actions.has(result.id)) {
|
||||
this.actions.set(result.id, observable.map(undefined, { deep: false }));
|
||||
}
|
||||
|
||||
const actionsMap = this.actions.get(result.id)!;
|
||||
|
||||
if (!actionsMap.has(Action)) {
|
||||
actionsMap.set(Action, new Action(result));
|
||||
}
|
||||
|
||||
return actionsMap.get(Action)! as T;
|
||||
}
|
||||
|
||||
updateResults(results: TResult[]): void {
|
||||
const keys = Array.from(this.actions.keys());
|
||||
|
||||
for (const key of keys) {
|
||||
if (!results.some(result => result.id === key)) {
|
||||
this.actions.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@ import { observable, makeObservable } from 'mobx';
|
||||
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import type { IExecutionContext } from '../IExecutionContext';
|
||||
import { DatabaseDataActions } from './DatabaseDataActions';
|
||||
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
|
||||
import type { IDatabaseDataActions } from './IDatabaseDataActions';
|
||||
import type { IDatabaseDataEditor, IDatabaseDataResultEditor } from './IDatabaseDataEditor';
|
||||
import type { IDatabaseDataResult } from './IDatabaseDataResult';
|
||||
import { DatabaseDataAccessMode, IDatabaseDataSource, IRequestInfo } from './IDatabaseDataSource';
|
||||
@@ -21,6 +24,7 @@ implements IDatabaseDataSource<TOptions, TResult> {
|
||||
dataFormat: ResultDataFormat;
|
||||
supportedDataFormats: ResultDataFormat[];
|
||||
editor: IDatabaseDataEditor<TResult> | null;
|
||||
actions: IDatabaseDataActions<TResult>;
|
||||
results: TResult[];
|
||||
offset: number;
|
||||
count: number;
|
||||
@@ -50,6 +54,7 @@ implements IDatabaseDataSource<TOptions, TResult> {
|
||||
activeSave: observable,
|
||||
});
|
||||
|
||||
this.actions = new DatabaseDataActions();
|
||||
this.access = DatabaseDataAccessMode.Default;
|
||||
this.results = [];
|
||||
this.editor = null;
|
||||
@@ -68,6 +73,17 @@ implements IDatabaseDataSource<TOptions, TResult> {
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
getAction<T extends IDatabaseDataAction<TResult>>(
|
||||
resultIndex: number,
|
||||
action: IDatabaseDataActionClass<TResult, T>
|
||||
): T {
|
||||
if (!this.hasResult(resultIndex)) {
|
||||
throw new Error('Result index out of range');
|
||||
}
|
||||
|
||||
return this.actions.get(this.results[resultIndex], action);
|
||||
}
|
||||
|
||||
abstract cancel(): Promise<boolean> | boolean;
|
||||
|
||||
hasResult(resultIndex: number): boolean {
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2021 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 type { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import type { IDatabaseDataResult } from './IDatabaseDataResult';
|
||||
|
||||
export interface IDatabaseDataActionClass<
|
||||
TResult extends IDatabaseDataResult,
|
||||
TAction extends IDatabaseDataAction<TResult>
|
||||
> {
|
||||
new (result: TResult): TAction;
|
||||
dataFormat: ResultDataFormat;
|
||||
}
|
||||
|
||||
export interface IDatabaseDataAction<TResult extends IDatabaseDataResult> {
|
||||
readonly result: TResult;
|
||||
updateResult: (result: TResult) => void;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2021 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 type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
|
||||
import type { IDatabaseDataResult } from './IDatabaseDataResult';
|
||||
|
||||
export interface IDatabaseDataActions<TResult extends IDatabaseDataResult> {
|
||||
get: <T extends IDatabaseDataAction<TResult>>(
|
||||
result: TResult,
|
||||
action: IDatabaseDataActionClass<TResult, T>
|
||||
) => T;
|
||||
|
||||
updateResults: (results: TResult[]) => void;
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
import type { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import type { IExecutionContext } from '../IExecutionContext';
|
||||
import type { IDatabaseDataAction, IDatabaseDataActionClass } from './IDatabaseDataAction';
|
||||
import type { IDatabaseDataActions } from './IDatabaseDataActions';
|
||||
import type { IDatabaseDataEditor, IDatabaseDataResultEditor } from './IDatabaseDataEditor';
|
||||
import type { IDatabaseDataResult } from './IDatabaseDataResult';
|
||||
|
||||
@@ -26,6 +28,7 @@ export interface IDatabaseDataSource<TOptions, TResult extends IDatabaseDataResu
|
||||
readonly access: DatabaseDataAccessMode;
|
||||
readonly dataFormat: ResultDataFormat;
|
||||
readonly supportedDataFormats: ResultDataFormat[];
|
||||
readonly actions: IDatabaseDataActions<TResult>;
|
||||
readonly editor: IDatabaseDataEditor<TResult> | null;
|
||||
readonly results: TResult[];
|
||||
readonly offset: number;
|
||||
@@ -41,6 +44,12 @@ export interface IDatabaseDataSource<TOptions, TResult extends IDatabaseDataResu
|
||||
|
||||
hasResult: (resultIndex: number) => boolean;
|
||||
|
||||
getAction: <T extends IDatabaseDataAction<TResult>>(
|
||||
resultIndex: number,
|
||||
action: IDatabaseDataActionClass<TResult, T>
|
||||
) => T;
|
||||
|
||||
/** @deprecated will be moved to getAction */
|
||||
getEditor: (resultIndex: number) => IDatabaseDataResultEditor<TResult>;
|
||||
getResult: (index: number) => TResult | null;
|
||||
|
||||
|
||||
@@ -2,10 +2,15 @@ import { manifest } from './manifest';
|
||||
|
||||
export default manifest;
|
||||
|
||||
export * from './DatabaseDataModel/Actions/DatabaseDataActionDecorator';
|
||||
export * from './DatabaseDataModel/Actions/DatabaseDataActionDecorator';
|
||||
export * from './DatabaseDataModel/DatabaseDataActions';
|
||||
export * from './DatabaseDataModel/DatabaseDataEditor';
|
||||
export * from './DatabaseDataModel/DatabaseDataFormat';
|
||||
export * from './DatabaseDataModel/DatabaseDataModel';
|
||||
export * from './DatabaseDataModel/DatabaseDataSource';
|
||||
export * from './DatabaseDataModel/IDatabaseDataAction';
|
||||
export * from './DatabaseDataModel/IDatabaseDataActions';
|
||||
export * from './DatabaseDataModel/IDatabaseDataEditor';
|
||||
export * from './DatabaseDataModel/IDatabaseDataModel';
|
||||
export * from './DatabaseDataModel/IDatabaseDataResult';
|
||||
|
||||
Reference in New Issue
Block a user