Skip to content

Commit

Permalink
CB-4570 add correct limits for text and blob columns in value panel (#…
Browse files Browse the repository at this point in the history
…2351)

* CB-4570 add correct limits for text and blob columns in value panel

* CB-4570 pr fixes

* CB-4570 adds shorter versions of limit messages

* CB-4570 pr fixes

* CB-4570 pr fixes

* CB-4570 code cleanup

* CB-4570 show more button moved to quota container

* CB-4570 code cleanup

* CB-4570 code cleanup

* CB-4570 quota placeholder to module css

* CB-4570 refactor: limit info in content action

* CB-4570 cleanup

* CB-4570 refactor: result set binary file implementation

* CB-4570 code clean

* CB-4570 adds QuotaPlaceholder getLimitInfo logic

* CB-4570 adds quota placeholder logic to not render when size is not truncated

* CB-4570 fix: shouldShowPasteButton reverted

* CB-4570 fix: show quota placeholder correctly

* CB-4570 code clean

* Revert "CB-4570 fix: show quota placeholder correctly"

This reverts commit d86b35e.

* CB-4570 fix: truncate image and text depending on current value panel presentation tab id

* Revert "Revert "CB-4570 fix: show quota placeholder correctly""

This reverts commit d5df008.

* CB-4570 code clean

* CB-4570 chore: dataContent has no image mentions

---------

Co-authored-by: s.teleshev <[email protected]>
Co-authored-by: Evgenia Bezborodova <[email protected]>
  • Loading branch information
3 people authored Feb 9, 2024
1 parent 1d497fe commit 898e7d9
Show file tree
Hide file tree
Showing 22 changed files with 196 additions and 154 deletions.
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export default [
['ui_upload', 'Upload'],
['ui_import', 'Import'],
['ui_view', 'View'],
['ui_show_more', 'Show more'],
['ui_limit', 'Limit'],
['ui_file_size', 'File size'],
['ui_processing_synchronization', 'Synchronization...'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/it.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export default [
['ui_upload', 'Upload'],
['ui_import', 'Import'],
['ui_view', 'View'],
['ui_show_more', 'Show more'],
['ui_limit', 'Limit'],
['ui_file_size', 'File size'],
['ui_processing_synchronization', 'Synchronization...'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export default [
['ui_upload', 'Загрузить'],
['ui_import', 'Импортировать'],
['ui_view', 'Смотреть'],
['ui_show_more', 'Показать больше'],
['ui_limit', 'Лимит'],
['ui_file_size', 'Размер файла'],
['ui_processing_synchronization', 'Синхронизация...'],
Expand Down
1 change: 1 addition & 0 deletions webapp/packages/core-localization/src/locales/zh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export default [
['ui_upload', 'Upload'],
['ui_import', 'Import'],
['ui_view', 'View'],
['ui_show_more', 'Show more'],
['ui_limit', 'Limit'],
['ui_file_size', 'File size'],
['ui_processing_synchronization', 'Synchronization...'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { IResultSetContentValue } from './IResultSetContentValue';

export interface IResultSetBinaryFileValue extends IResultSetContentValue {
export interface IResultSetBinaryValue extends IResultSetContentValue {
binary: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
* Licensed under the Apache License, Version 2.0.
* you may not use this file except in compliance with the License.
*/
import type { IResultSetContentValue } from './IResultSetContentValue';
import type { IResultSetElementKey } from './IResultSetDataKey';

export interface IResultSetDataContentAction {
activeElement: IResultSetElementKey | null;
isContentTruncated: (content: IResultSetContentValue) => boolean;
isBlobTruncated: (element: IResultSetElementKey) => boolean;
isTextTruncated: (element: IResultSetElementKey) => boolean;
isDownloadable: (element: IResultSetElementKey) => boolean;
getFileDataUrl: (element: IResultSetElementKey) => Promise<string>;
resolveFileDataUrl: (element: IResultSetElementKey) => Promise<string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,12 @@ import { makeObservable, observable } from 'mobx';

import { QuotasService } from '@cloudbeaver/core-root';
import { GraphQLService, ResultDataFormat } from '@cloudbeaver/core-sdk';
import { download, GlobalConstants } from '@cloudbeaver/core-utils';
import { bytesToSize, download, GlobalConstants, isNotNullDefined } from '@cloudbeaver/core-utils';

import { DatabaseDataAction } from '../../DatabaseDataAction';
import type { IDatabaseDataSource } from '../../IDatabaseDataSource';
import type { IDatabaseResultSet } from '../../IDatabaseResultSet';
import { databaseDataAction } from '../DatabaseDataActionDecorator';
import type { IResultSetContentValue } from './IResultSetContentValue';
import type { IResultSetDataContentAction } from './IResultSetDataContentAction';
import type { IResultSetElementKey } from './IResultSetDataKey';
import { isResultSetContentValue } from './isResultSetContentValue';
Expand Down Expand Up @@ -57,8 +56,53 @@ export class ResultSetDataContentAction extends DatabaseDataAction<any, IDatabas
});
}

isContentTruncated(content: IResultSetContentValue) {
return (content.contentLength ?? 0) > this.quotasService.getQuota('sqlBinaryPreviewMaxLength');
getLimitInfo(elementKey: IResultSetElementKey) {
const isTextColumn = this.format.isText(elementKey);
const isBlob = this.format.isBinary(elementKey);
const result = {
limit: undefined as number | undefined,
limitWithSize: undefined as string | undefined,
};

if (isTextColumn) {
result.limit = this.quotasService.getQuota('sqlTextPreviewMaxLength');
}

if (isBlob) {
result.limit = this.quotasService.getQuota('sqlBinaryPreviewMaxLength');
}

if (result.limit) {
result.limitWithSize = bytesToSize(result.limit);
}

return result;
}

isBlobTruncated(elementKey: IResultSetElementKey) {
const limit = this.getLimitInfo(elementKey).limit;
const content = this.format.get(elementKey);
const cachedBlobUrl = this.retrieveFileDataUrlFromCache(elementKey);
const isLoadedFullBlob = Boolean(cachedBlobUrl) && this.format.isBinary(elementKey);

if (!isNotNullDefined(limit) || !isResultSetContentValue(content) || isLoadedFullBlob || !this.format.isBinary(elementKey)) {
return false;
}

return (content.contentLength ?? 0) > limit;
}

isTextTruncated(elementKey: IResultSetElementKey) {
const limit = this.getLimitInfo(elementKey).limit;
const content = this.format.get(elementKey);
const cachedFullText = this.retrieveFileFullTextFromCache(elementKey);
const isLoadedFullText = Boolean(cachedFullText) && this.format.isText(elementKey);

if (!isNotNullDefined(limit) || !isResultSetContentValue(content) || isLoadedFullText) {
return false;
}

return (content.contentLength ?? 0) > limit;
}

isDownloadable(element: IResultSetElementKey) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,16 @@ export class ResultSetFormatAction
return false;
}

isText(key: IResultSetPartialKey): boolean {
if (!key?.column) {
return false;
}

const column = this.view.getColumn(key.column);

return column?.dataKind?.toLocaleLowerCase() === 'string';
}

getHeaders(): string[] {
return this.view.columns.map(column => column.name!).filter(name => name !== undefined);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2024 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 { IResultSetBinaryValue } from './IResultSetBinaryValue';
import { isResultSetContentValue } from './isResultSetContentValue';

export function isResultSetBinaryValue(value: any): value is IResultSetBinaryValue {
return isResultSetContentValue(value) && 'binary' in value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface IResultActionsArgs {
model: IDatabaseDataModel<any, IDatabaseResultSet>;
}

export function useResultActions({ model, resultIndex }: IResultActionsArgs) {
export function useResultSetActions({ model, resultIndex }: IResultActionsArgs) {
return useObservableRef(
() => ({
get dataAction(): ResultSetDataAction {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ import { ActionIconButton, Button, Container, Fill, s, useObservableRef, useS, u
import { selectFiles } from '@cloudbeaver/core-browser';
import { useService } from '@cloudbeaver/core-di';
import { NotificationService } from '@cloudbeaver/core-events';
import { QuotasService } from '@cloudbeaver/core-root';
import { type TabContainerPanelComponent, useTabLocalState } from '@cloudbeaver/core-ui';
import { bytesToSize, download, getMIME, isImageFormat, isValidUrl } from '@cloudbeaver/core-utils';

import { createResultSetBlobValue } from '../../DatabaseDataModel/Actions/ResultSet/createResultSetBlobValue';
import type { IResultSetElementKey } from '../../DatabaseDataModel/Actions/ResultSet/IResultSetDataKey';
import { isResultSetBinaryValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetBinaryValue';
import { isResultSetBlobValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetBlobValue';
import { isResultSetContentValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetContentValue';
import { isResultSetFileValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetFileValue';
Expand Down Expand Up @@ -66,7 +66,6 @@ export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelP
function ImageValuePresentation({ model, resultIndex }) {
const translate = useTranslate();
const notificationService = useService(NotificationService);
const quotasService = useService(QuotasService);
const style = useS(styles);

const state = useTabLocalState(() =>
Expand Down Expand Up @@ -123,7 +122,7 @@ export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelP
return URL.createObjectURL(this.cellValue.blob);
}

if (isResultSetContentValue(this.cellValue) && this.cellValue.binary) {
if (isResultSetBinaryValue(this.cellValue)) {
return `data:${getMIME(this.cellValue.binary)};base64,${this.cellValue.binary}`;
} else if (typeof this.cellValue === 'string' && isValidUrl(this.cellValue) && isImageFormat(this.cellValue)) {
return this.cellValue;
Expand Down Expand Up @@ -154,12 +153,14 @@ export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelP
if (isResultSetFileValue(this.cellValue)) {
return false;
}
if (isResultSetContentValue(this.cellValue)) {
if (this.cellValue.binary) {
return this.contentAction.isContentTruncated(this.cellValue);
}
}
return false;

return this.selectedCell && this.contentAction.isBlobTruncated(this.selectedCell);
},
get shouldShowImage() {
const isFullImage = !this.truncated && this.savedSrc;
const isImage = this.src && !this.truncated && !this.savedSrc;

return isFullImage || isImage;
},
async save() {
try {
Expand Down Expand Up @@ -206,27 +207,28 @@ export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelP
const loading = model.isLoading();
const value = data.cellValue;

if (data.truncated && !data.savedSrc && isResultSetContentValue(value)) {
const limit = bytesToSize(quotasService.getQuota('sqlBinaryPreviewMaxLength'));
const valueSize = bytesToSize(value.contentLength ?? 0);
const load = async () => {
if (!data.selectedCell) {
return;
}

const load = async () => {
if (!data.selectedCell) {
return;
}
try {
await data.contentAction.resolveFileDataUrl(data.selectedCell);
} catch (exception: any) {
notificationService.logException(exception, 'data_viewer_presentation_value_content_download_error');
}
};

try {
await data.contentAction.resolveFileDataUrl(data.selectedCell);
} catch (exception: any) {
notificationService.logException(exception, 'data_viewer_presentation_value_content_download_error');
}
};
const valueSize = bytesToSize(isResultSetContentValue(value) ? value.contentLength ?? 0 : 0);
const isDownloadable = data.selectedCell && data.contentAction.isDownloadable(data.selectedCell);

return (
<Container vertical>
<Container fill overflow center>
<QuotaPlaceholder limit={limit} size={valueSize}>
{data.selectedCell && data.contentAction.isDownloadable(data.selectedCell) && (
return (
<Container vertical>
<Container fill overflow center>
{data.shouldShowImage && <img src={data.src} className={s(style, { img: true, stretch: state.stretch })} />}
{data.truncated ? (
<QuotaPlaceholder model={data.model} resultIndex={data.resultIndex} elementKey={data.selectedCell}>
{isDownloadable && (
<Button
disabled={loading}
loading={
Expand All @@ -235,20 +237,11 @@ export const ImageValuePresentation: TabContainerPanelComponent<IDataValuePanelP
}
onClick={load}
>
{translate('ui_view')}
{`${translate('ui_view')} (${valueSize})`}
</Button>
)}
</QuotaPlaceholder>
</Container>
<Tools loading={loading} onSave={save} onUpload={upload} />
</Container>
);
}

return (
<Container vertical>
<Container fill overflow center>
<img src={data.src} className={s(style, { img: true, stretch: state.stretch })} />
) : null}
</Container>
<Tools loading={loading} stretch={state.stretch} onToggleStretch={state.toggleStretch} onSave={save} onUpload={upload} />
</Container>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.link {
margin-left: 4px;
}

.limitWord {
text-transform: lowercase;
}
Loading

0 comments on commit 898e7d9

Please sign in to comment.