feat(plugin-data-viewer): CB-908 image value presentation

This commit is contained in:
Wroud
2021-06-03 19:29:53 +03:00
parent b647b43581
commit 0216f133ae
10 changed files with 179 additions and 0 deletions
@@ -0,0 +1,15 @@
/*
* 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.
*/
export interface IResultSetContentValue {
$type: 'content';
binary?: string;
text?: string;
contentType?: string;
contentLength?: number;
}
@@ -12,6 +12,7 @@ import { DatabaseDataAction } from '../../DatabaseDataAction';
import type { IDatabaseResultSet } from '../../IDatabaseResultSet';
import { databaseDataAction } from '../DatabaseDataActionDecorator';
import type { IDatabaseDataResultAction } from '../IDatabaseDataResultAction';
import type { IResultSetContentValue } from './IResultSetContentValue';
import type { IResultSetElementKey } from './IResultSetElementKey';
@databaseDataAction()
@@ -27,6 +28,20 @@ export class ResultSetDataAction extends DatabaseDataAction<any, IDatabaseResult
return this.result.data.rows?.[cell.row]?.[cell.column];
}
getContent(cell: IResultSetElementKey): IResultSetContentValue | null {
const value = this.getCellValue(cell);
if (
value !== null
&& typeof value === 'object'
&& '$type' in value
&& value.$type === 'content'
) {
return value;
}
return null;
}
getColumn(columnIndex: number) {
if (!this.result.data?.columns) {
return undefined;
@@ -0,0 +1,55 @@
/*
* 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 { observer } from 'mobx-react-lite';
import styled, { css } from 'reshadow';
import type { TabContainerPanelComponent } from '@cloudbeaver/core-blocks';
import { useStyles } from '@cloudbeaver/core-theming';
import { getMIME } from '@cloudbeaver/core-utils';
import { ResultSetDataAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetDataAction';
import { ResultSetSelectAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction';
import type { IDatabaseResultSet } from '../../DatabaseDataModel/IDatabaseResultSet';
import type { IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService';
const styles = css`
img {
margin: auto;
max-width: 100%;
max-height: 100%;
}
`;
export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelProps<any, IDatabaseResultSet>> = observer(function ImageValuePresentation({
model,
resultIndex,
}) {
const selection = model.source.getAction(resultIndex, ResultSetSelectAction);
const selectedCells = selection.getSelectedElements();
const focusCell = selection.getFocusedElement();
let src: string | undefined;
if (selectedCells.length > 0 || focusCell) {
const firstSelectedCell = selectedCells[0] || focusCell;
const content = model.source
.getAction(resultIndex, ResultSetDataAction)
.getContent(firstSelectedCell);
if (content?.binary) {
src = `data:${getMIME(content.binary)};base64,${content.binary}`;
}
}
return styled(useStyles(styles))(
<img src={src} />
);
});
@@ -0,0 +1,62 @@
/*
* 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
import { getMIME } from '@cloudbeaver/core-utils';
import type { IResultSetContentValue } from '../../DatabaseDataModel/Actions/ResultSet/IResultSetContentValue';
import { ResultSetDataAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetDataAction';
import { ResultSetSelectAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction';
import { DataValuePanelService } from '../../TableViewer/ValuePanel/DataValuePanelService';
import { ImageValuePresentation } from './ImageValuePresentation';
@injectable()
export class ImageValuePresentationBootstrap extends Bootstrap {
constructor(private readonly dataValuePanelService: DataValuePanelService) {
super();
}
register(): void | Promise<void> {
this.dataValuePanelService.add({
key: 'image-presentation',
options: { dataFormat: [ResultDataFormat.Resultset] },
name: 'data_viewer_presentation_value_image_title',
order: 1,
panel: () => ImageValuePresentation,
isHidden: (_, context) => {
if (!context || !context.model.source.hasResult(context.resultIndex)) {
return true;
}
const selection = context.model.source.getAction(context.resultIndex, ResultSetSelectAction);
const data = context.model.source.getAction(context.resultIndex, ResultSetDataAction);
const selectedCells = selection.getSelectedElements();
const focusedElement = selection.getFocusedElement();
if (selectedCells.length > 0 || focusedElement) {
const firstSelectedCell = selectedCells[0] || focusedElement;
return !this.isImage(data.getContent(firstSelectedCell));
}
return true;
},
});
}
load(): void { }
private isImage(value: IResultSetContentValue | null) {
if (value !== null && 'binary' in value) {
return getMIME(value.binary || '') !== null;
}
return false;
}
}
@@ -2,6 +2,7 @@ import { manifest } from './manifest';
export default manifest;
export * from './DatabaseDataModel/Actions/ResultSet/IResultSetContentValue';
export * from './DatabaseDataModel/Actions/ResultSet/IResultSetElementKey';
export * from './DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction';
export * from './DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction';
@@ -6,4 +6,5 @@ export default [
['data_viewer_statistics_updated_rows', 'Updated Rows:'],
['data_viewer_presentation_value_title', 'Value'],
['data_viewer_presentation_value_text_title', 'Text'],
['data_viewer_presentation_value_image_title', 'Image'],
];
@@ -3,4 +3,5 @@ export default [
['data_viewer_nodata_message', 'Нет данных для отображения'],
['data_viewer_presentation_value_title', 'Значение'],
['data_viewer_presentation_value_text_title', 'Текст'],
['data_viewer_presentation_value_image_title', 'Изображение'],
];
@@ -18,6 +18,7 @@ import { TableHeaderService } from './TableViewer/TableHeader/TableHeaderService
import { TableViewerStorageService } from './TableViewer/TableViewerStorageService';
import { DataValuePanelBootstrap } from './TableViewer/ValuePanel/DataValuePanelBootstrap';
import { DataValuePanelService } from './TableViewer/ValuePanel/DataValuePanelService';
import { ImageValuePresentationBootstrap } from './ValuePanelPresentation/ImageValue/ImageValuePresentationBootstrap';
import { TextValuePresentationBootstrap } from './ValuePanelPresentation/TextValue/TextValuePresentationBootstrap';
export const manifest: PluginManifest = {
@@ -36,6 +37,7 @@ export const manifest: PluginManifest = {
LocaleService,
DataValuePanelService,
TextValuePresentationBootstrap,
ImageValuePresentationBootstrap,
DataValuePanelBootstrap,
],
};