mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
dbeaver/pro#6026 feat: merge value panel tabs in one group (#3829)
* dbeaver/pro#6026 feat: merge value panel tabs in one group move all text representations to the first tab level specific representation is used if present (boolean, image) auto type detection is used only for text * dbeaver/pro#6026 refactor: remove unused CSS files for TextValuePresentation * dbeaver/pro#6026 refactor: remove automatic state update in ValuePanel component * dbeaver/pro#6026 refactor: update content type handling in ValuePanel Move all the content type determination logic into the hook Simplify the component * dbeaver/pro#6026 refactor: consolidate content type handling in useAutoContentType hook * dbeaver/pro#6026 fix: show scroll on tabs in value panel when overflow
This commit is contained in:
+2
-1
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,6 +13,7 @@ import type { IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataMo
|
||||
|
||||
export interface IDataValuePanelOptions {
|
||||
dataFormat: ResultDataFormat[];
|
||||
isTextPresentation?: boolean;
|
||||
}
|
||||
|
||||
export interface IDataValuePanelProps {
|
||||
|
||||
@@ -22,6 +22,9 @@ import ValuePanelTab from './shared/ValuePanelTab.module.css';
|
||||
import { IDatabaseDataSelectAction } from '../../DatabaseDataModel/Actions/IDatabaseDataSelectAction.js';
|
||||
import { IDatabaseDataResultAction } from '../../DatabaseDataModel/Actions/IDatabaseDataResultAction.js';
|
||||
import { IDatabaseDataMetadataAction } from '../../DatabaseDataModel/Actions/IDatabaseDataMetadataAction.js';
|
||||
import { IDatabaseDataFormatAction } from '../../DatabaseDataModel/Actions/IDatabaseDataFormatAction.js';
|
||||
import type { IGridDataKey } from '../../DatabaseDataModel/Actions/Grid/IGridDataKey.js';
|
||||
import { useContentType } from '../../ValuePanelPresentation/TextValue/useContentType.js';
|
||||
|
||||
const tabListRegistry: StyleRegistry = [[TabStyles, { mode: 'append', styles: [ValuePanelTab] }]];
|
||||
|
||||
@@ -35,7 +38,7 @@ export const ValuePanel: DataPresentationComponent = observer(function ValuePane
|
||||
const selectAction = model.source.tryGetAction(resultIndex, IDatabaseDataSelectAction);
|
||||
const dataResultAction = model.source.tryGetAction(resultIndex, IDatabaseDataResultAction);
|
||||
const metadataAction = model.source.getAction(resultIndex, IDatabaseDataMetadataAction);
|
||||
const activeElements = selectAction?.getActiveElements();
|
||||
const activeElements = selectAction?.getActiveElements() as IGridDataKey[] | undefined;
|
||||
let elementKey: string | null = null;
|
||||
const style = useS(styles);
|
||||
|
||||
@@ -58,13 +61,14 @@ export const ValuePanel: DataPresentationComponent = observer(function ValuePane
|
||||
);
|
||||
|
||||
const displayed = service.getDisplayed({ dataFormat, model, resultIndex });
|
||||
let currentTabId = state.currentTabId;
|
||||
|
||||
const hasCurrentTabCells = currentTabId && displayed.some(tab => tab.key === currentTabId);
|
||||
|
||||
if (displayed.length > 0 && !hasCurrentTabCells) {
|
||||
currentTabId = displayed[0]!.key;
|
||||
}
|
||||
const currentTabId = useContentType({
|
||||
model: model as any,
|
||||
currentContentType: state.currentTabId,
|
||||
elementKey: activeElements && activeElements.length > 0 ? activeElements[0] : undefined,
|
||||
formatAction: model.source.tryGetAction(resultIndex, IDatabaseDataFormatAction),
|
||||
displayed,
|
||||
});
|
||||
|
||||
return (
|
||||
<TabsState
|
||||
|
||||
+2
@@ -9,6 +9,8 @@
|
||||
.tabList {
|
||||
composes: theme-background-secondary theme-border-color-background theme-text-on-secondary from global;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
|
||||
+7
-50
@@ -8,10 +8,10 @@
|
||||
import { observable } from 'mobx';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { ActionIconButton, Container, Group, Loader, s, SContext, type StyleRegistry, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { ActionIconButton, Container, Group, Loader, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { type TabContainerPanelComponent, TabList, TabsState, TabStyles, useTabLocalState } from '@cloudbeaver/core-ui';
|
||||
import { type TabContainerPanelComponent, useTabLocalState } from '@cloudbeaver/core-ui';
|
||||
|
||||
import { ResultSetDataContentAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetDataContentAction.js';
|
||||
import { DataViewerService } from '../../DataViewerService.js';
|
||||
@@ -19,21 +19,16 @@ import { isResultSetDataModel } from '../../ResultSet/isResultSetDataModel.js';
|
||||
import type { IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
import { getDefaultLineWrapping } from './getDefaultLineWrapping.js';
|
||||
import { isTextValueReadonly } from './isTextValueReadonly.js';
|
||||
import styles from './shared/TextValuePresentation.module.css';
|
||||
import TextValuePresentationTab from './shared/TextValuePresentationTab.module.css';
|
||||
import { TextValueEditor } from './TextValueEditor.js';
|
||||
import { TextValuePresentationService } from './TextValuePresentationService.js';
|
||||
import { TextValueTruncatedMessage } from './TextValueTruncatedMessage.js';
|
||||
import { useAutoContentType } from './useAutoContentType.js';
|
||||
import { useTextValueGetter } from './useTextValueGetter.js';
|
||||
import { IDatabaseDataSelectAction } from '../../DatabaseDataModel/Actions/IDatabaseDataSelectAction.js';
|
||||
import { IDatabaseDataFormatAction } from '../../DatabaseDataModel/Actions/IDatabaseDataFormatAction.js';
|
||||
import { IDatabaseDataEditAction } from '../../DatabaseDataModel/Actions/IDatabaseDataEditAction.js';
|
||||
import { GridSelectAction } from '../../DatabaseDataModel/Actions/Grid/GridSelectAction.js';
|
||||
|
||||
const tabRegistry: StyleRegistry = [[TabStyles, { mode: 'append', styles: [TextValuePresentationTab] }]];
|
||||
|
||||
export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelProps> = observer(function TextValuePresentation({
|
||||
tabId,
|
||||
model: unknownModel,
|
||||
resultIndex,
|
||||
dataFormat,
|
||||
@@ -44,9 +39,7 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
}
|
||||
const translate = useTranslate();
|
||||
const notificationService = useService(NotificationService);
|
||||
const textValuePresentationService = useService(TextValuePresentationService);
|
||||
const dataViewerService = useService(DataViewerService);
|
||||
const style = useS(styles, TextValuePresentationTab);
|
||||
const selectAction = model.source.getAction(resultIndex, IDatabaseDataSelectAction, GridSelectAction);
|
||||
const formatAction = model.source.getAction(resultIndex, IDatabaseDataFormatAction);
|
||||
const activeElements = selectAction.getActiveElements();
|
||||
@@ -57,33 +50,21 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
const state = useTabLocalState(() =>
|
||||
observable({
|
||||
lineWrapping: null as boolean | null,
|
||||
currentContentType: null as string | null,
|
||||
|
||||
setContentType(contentType: string | null) {
|
||||
this.currentContentType = contentType;
|
||||
},
|
||||
setLineWrapping(lineWrapping: boolean | null) {
|
||||
this.lineWrapping = lineWrapping;
|
||||
},
|
||||
}),
|
||||
);
|
||||
const contentType = useAutoContentType({
|
||||
dataFormat,
|
||||
model,
|
||||
resultIndex,
|
||||
currentContentType: state.currentContentType,
|
||||
elementKey: firstSelectedCell,
|
||||
formatAction,
|
||||
});
|
||||
|
||||
const textValueGetter = useTextValueGetter({
|
||||
contentAction,
|
||||
editAction,
|
||||
formatAction,
|
||||
dataFormat,
|
||||
contentType,
|
||||
contentType: tabId,
|
||||
elementKey: firstSelectedCell,
|
||||
});
|
||||
const autoLineWrapping = getDefaultLineWrapping(contentType);
|
||||
const autoLineWrapping = getDefaultLineWrapping(tabId);
|
||||
const lineWrapping = state.lineWrapping ?? autoLineWrapping;
|
||||
const isReadonly = isTextValueReadonly({ model, resultIndex, contentAction, cell: firstSelectedCell, formatAction, editAction });
|
||||
const canSave = firstSelectedCell && contentAction.isDownloadable(firstSelectedCell) && dataViewerService.canExportData;
|
||||
@@ -106,40 +87,16 @@ export const TextValuePresentation: TabContainerPanelComponent<IDataValuePanelPr
|
||||
}
|
||||
}
|
||||
|
||||
function selectTabHandler(tabId: string) {
|
||||
// currentContentType may be selected automatically we don't want to change state in this case
|
||||
if (tabId !== contentType) {
|
||||
state.setContentType(tabId);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleLineWrappingHandler() {
|
||||
state.setLineWrapping(!lineWrapping);
|
||||
}
|
||||
|
||||
return (
|
||||
<Container vertical gap dense overflow>
|
||||
<Container keepSize center overflow>
|
||||
<Container keepSize>
|
||||
<TabsState
|
||||
dataFormat={dataFormat}
|
||||
resultIndex={resultIndex}
|
||||
container={textValuePresentationService.tabs}
|
||||
currentTabId={contentType}
|
||||
model={model}
|
||||
lazy
|
||||
onChange={tab => selectTabHandler(tab.tabId)}
|
||||
>
|
||||
<SContext registry={tabRegistry}>
|
||||
<TabList className={s(style, { tabList: true, textValuePresentationTab: true, underline: true })} underline />
|
||||
</SContext>
|
||||
</TabsState>
|
||||
</Container>
|
||||
</Container>
|
||||
<Loader suspense>
|
||||
<Group overflow maximum box>
|
||||
<TextValueEditor
|
||||
contentType={contentType}
|
||||
contentType={tabId}
|
||||
lineWrapping={lineWrapping}
|
||||
readonly={isReadonly}
|
||||
valueGetter={textValueGetter}
|
||||
|
||||
+58
-63
@@ -1,87 +1,82 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2025 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 React from 'react';
|
||||
|
||||
import { importLazyComponent } from '@cloudbeaver/core-blocks';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
|
||||
import { isResultSetDataSource } from '../../ResultSet/ResultSetDataSource.js';
|
||||
import { DataValuePanelService } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
import { DataValuePanelService, type IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
import { isBlobPresentationAvailable } from './isTextValuePresentationAvailable.js';
|
||||
import { TextValuePresentationService } from './TextValuePresentationService.js';
|
||||
|
||||
const TextValuePresentation = importLazyComponent(() => import('./TextValuePresentation.js').then(module => module.TextValuePresentation));
|
||||
|
||||
@injectable(() => [TextValuePresentationService, DataValuePanelService])
|
||||
const PRESENTATIONS = [
|
||||
{
|
||||
key: 'text/plain',
|
||||
name: 'data_viewer_presentation_value_text_title',
|
||||
},
|
||||
{
|
||||
key: 'text/html',
|
||||
name: 'data_viewer_presentation_value_text_html_title',
|
||||
},
|
||||
{
|
||||
key: 'text/xml',
|
||||
name: 'data_viewer_presentation_value_text_xml_title',
|
||||
},
|
||||
{
|
||||
key: 'application/json',
|
||||
name: 'data_viewer_presentation_value_text_json_title',
|
||||
},
|
||||
{
|
||||
key: 'application/octet-stream;type=hex',
|
||||
name: 'data_viewer_presentation_value_text_hex_title',
|
||||
isHidden: (context: IDataValuePanelProps | undefined) => !isBlobPresentationAvailable(context),
|
||||
},
|
||||
{
|
||||
key: 'application/octet-stream;type=base64',
|
||||
name: 'data_viewer_presentation_value_text_base64_title',
|
||||
isHidden: (context: IDataValuePanelProps | undefined) => !isBlobPresentationAvailable(context),
|
||||
},
|
||||
];
|
||||
|
||||
@injectable(() => [DataValuePanelService])
|
||||
export class TextValuePresentationBootstrap extends Bootstrap {
|
||||
constructor(
|
||||
private readonly textValuePresentationService: TextValuePresentationService,
|
||||
private readonly dataValuePanelService: DataValuePanelService,
|
||||
) {
|
||||
constructor(private readonly dataValuePanelService: DataValuePanelService) {
|
||||
super();
|
||||
}
|
||||
|
||||
override register(): void {
|
||||
this.dataValuePanelService.add({
|
||||
key: 'text-presentation',
|
||||
options: {
|
||||
dataFormat: [ResultDataFormat.Resultset],
|
||||
},
|
||||
name: 'data_viewer_presentation_value_text_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => TextValuePresentation,
|
||||
isHidden(_, props) {
|
||||
return !props || !props.model.source.hasResult(props.resultIndex) || !isResultSetDataSource(props.model.source);
|
||||
},
|
||||
});
|
||||
for (const presentation of PRESENTATIONS) {
|
||||
this.dataValuePanelService.add({
|
||||
key: presentation.key,
|
||||
options: {
|
||||
dataFormat: [ResultDataFormat.Resultset],
|
||||
isTextPresentation: true,
|
||||
},
|
||||
name: presentation.name,
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => TextValuePresentation,
|
||||
isHidden: (_, props) => {
|
||||
if (!props || !props.model.source.hasResult(props.resultIndex) || !isResultSetDataSource(props.model.source)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.textValuePresentationService.add({
|
||||
key: 'text/plain',
|
||||
name: 'data_viewer_presentation_value_text_plain_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => React.Fragment,
|
||||
});
|
||||
this.textValuePresentationService.add({
|
||||
key: 'text/html',
|
||||
name: 'data_viewer_presentation_value_text_html_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => React.Fragment,
|
||||
// isHidden: (_, context) => isBlobPresentationAvailable(context),
|
||||
});
|
||||
this.textValuePresentationService.add({
|
||||
key: 'text/xml',
|
||||
name: 'data_viewer_presentation_value_text_xml_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => React.Fragment,
|
||||
// isHidden: (_, context) => isBlobPresentationAvailable(context),
|
||||
});
|
||||
this.textValuePresentationService.add({
|
||||
key: 'application/json',
|
||||
name: 'data_viewer_presentation_value_text_json_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => React.Fragment,
|
||||
// isHidden: (_, context) => isBlobPresentationAvailable(context),
|
||||
});
|
||||
if (!presentation.isHidden) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.textValuePresentationService.add({
|
||||
key: 'application/octet-stream;type=hex',
|
||||
name: 'data_viewer_presentation_value_text_hex_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => React.Fragment,
|
||||
isHidden: (_, context) => !isBlobPresentationAvailable(context),
|
||||
});
|
||||
this.textValuePresentationService.add({
|
||||
key: 'application/octet-stream;type=base64',
|
||||
name: 'data_viewer_presentation_value_text_base64_title',
|
||||
order: Number.MAX_SAFE_INTEGER,
|
||||
panel: () => React.Fragment,
|
||||
isHidden: (_, context) => !isBlobPresentationAvailable(context),
|
||||
});
|
||||
return presentation.isHidden({
|
||||
dataFormat: props.dataFormat,
|
||||
model: props.model,
|
||||
resultIndex: props.resultIndex,
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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 { injectable } from '@cloudbeaver/core-di';
|
||||
import { type ITabInfo, type ITabInfoOptions, TabsContainer } from '@cloudbeaver/core-ui';
|
||||
|
||||
import { type IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataModel.js';
|
||||
import { ResultSetDataSource } from '../../ResultSet/ResultSetDataSource.js';
|
||||
import type { IDataValuePanelOptions, IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
|
||||
export interface ITextValuePanelProps extends Omit<IDataValuePanelProps, 'model'> {
|
||||
model: IDatabaseDataModel<ResultSetDataSource>;
|
||||
}
|
||||
|
||||
@injectable()
|
||||
export class TextValuePresentationService {
|
||||
readonly tabs: TabsContainer<ITextValuePanelProps, IDataValuePanelOptions>;
|
||||
|
||||
constructor() {
|
||||
this.tabs = new TabsContainer('Value presentation');
|
||||
}
|
||||
|
||||
get(tabId: string): ITabInfo<ITextValuePanelProps, IDataValuePanelOptions> | undefined {
|
||||
return this.tabs.getTabInfo(tabId);
|
||||
}
|
||||
|
||||
add(tabInfo: ITabInfoOptions<ITextValuePanelProps, IDataValuePanelOptions>): void {
|
||||
this.tabs.add(tabInfo);
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -9,9 +9,9 @@ import { isResultSetBinaryValue } from '@dbeaver/result-set-api';
|
||||
import { isResultSetBlobValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetBlobValue.js';
|
||||
import { ResultSetSelectAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetSelectAction.js';
|
||||
import { ResultSetViewAction } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetViewAction.js';
|
||||
import { type ITextValuePanelProps } from './TextValuePresentationService.js';
|
||||
import type { IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
|
||||
export function isBlobPresentationAvailable(context: ITextValuePanelProps | undefined): boolean {
|
||||
export function isBlobPresentationAvailable(context: IDataValuePanelProps | undefined): boolean {
|
||||
const source = context?.model.source;
|
||||
if (!context || !source?.hasResult(context.resultIndex)) {
|
||||
return true;
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.tabList {
|
||||
composes: theme-border-color-background theme-background-background from global;
|
||||
overflow: auto;
|
||||
border-radius: var(--theme-group-element-radius);
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
.tab {
|
||||
composes: theme-ripple theme-background-surface theme-text-text-primary-on-light from global;
|
||||
}
|
||||
|
||||
.textValuePresentationTab.underline .tab {
|
||||
border-bottom: 0;
|
||||
|
||||
&:global([aria-selected='false']) {
|
||||
border-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
+17
-27
@@ -5,25 +5,23 @@
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import type { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
import type { ITabInfo } from '@cloudbeaver/core-ui';
|
||||
import { isResultSetContentValue } from '@dbeaver/result-set-api';
|
||||
|
||||
import { isResultSetBlobValue } from '../../DatabaseDataModel/Actions/ResultSet/isResultSetBlobValue.js';
|
||||
import type { IResultSetValue } from '../../DatabaseDataModel/Actions/ResultSet/ResultSetFormatAction.js';
|
||||
import type { IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataModel.js';
|
||||
import { ResultSetDataSource } from '../../ResultSet/ResultSetDataSource.js';
|
||||
import { TextValuePresentationService } from './TextValuePresentationService.js';
|
||||
import type { IDatabaseDataFormatAction } from '../../DatabaseDataModel/Actions/IDatabaseDataFormatAction.js';
|
||||
import type { IGridDataKey } from '../../DatabaseDataModel/Actions/Grid/IGridDataKey.js';
|
||||
import { isResultSetDataModel } from '../../ResultSet/isResultSetDataModel.js';
|
||||
import type { IDatabaseDataSource } from '../../DatabaseDataModel/IDatabaseDataSource.js';
|
||||
import type { IDataValuePanelOptions, IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
|
||||
interface Args {
|
||||
resultIndex: number;
|
||||
model: IDatabaseDataModel<ResultSetDataSource>;
|
||||
dataFormat: ResultDataFormat | null;
|
||||
currentContentType: string | null;
|
||||
interface UseAutoContentTypeArgs {
|
||||
model: IDatabaseDataModel<IDatabaseDataSource>;
|
||||
elementKey?: IGridDataKey;
|
||||
formatAction: IDatabaseDataFormatAction;
|
||||
formatAction?: IDatabaseDataFormatAction;
|
||||
displayed: Array<ITabInfo<IDataValuePanelProps, IDataValuePanelOptions>>;
|
||||
}
|
||||
|
||||
const DEFAULT_CONTENT_TYPE = 'text/plain';
|
||||
@@ -55,24 +53,16 @@ function preprocessDefaultContentType(contentType: string | null | undefined) {
|
||||
return DEFAULT_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
export function useAutoContentType({ dataFormat, model, formatAction, resultIndex, currentContentType, elementKey }: Args) {
|
||||
const textValuePresentationService = useService(TextValuePresentationService);
|
||||
const activeTabs = textValuePresentationService.tabs.getDisplayed({
|
||||
dataFormat: dataFormat,
|
||||
model,
|
||||
resultIndex: resultIndex,
|
||||
});
|
||||
export function useAutoContentType({ displayed, formatAction, model, elementKey }: UseAutoContentTypeArgs): string | null {
|
||||
const isAllTextType = displayed.every(tab => tab.options?.isTextPresentation);
|
||||
const isAutoType = isAllTextType && formatAction && isResultSetDataModel(model);
|
||||
|
||||
if (!isAutoType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const contentValue = elementKey ? formatAction.get(elementKey) : null;
|
||||
const contentValueType = getContentTypeFromResultSetValue(contentValue);
|
||||
const defaultContentType = preprocessDefaultContentType(contentValueType);
|
||||
|
||||
if (currentContentType === null) {
|
||||
currentContentType = defaultContentType;
|
||||
}
|
||||
|
||||
if (activeTabs.length > 0 && !activeTabs.some(tab => tab.key === currentContentType)) {
|
||||
currentContentType = activeTabs[0]!.key;
|
||||
}
|
||||
|
||||
return currentContentType;
|
||||
return preprocessDefaultContentType(contentValueType);
|
||||
}
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 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 { ITabInfo } from '@cloudbeaver/core-ui';
|
||||
import type { IDatabaseDataModel } from '../../DatabaseDataModel/IDatabaseDataModel.js';
|
||||
import type { IDatabaseDataFormatAction } from '../../DatabaseDataModel/Actions/IDatabaseDataFormatAction.js';
|
||||
import type { IGridDataKey } from '../../DatabaseDataModel/Actions/Grid/IGridDataKey.js';
|
||||
import type { IDatabaseDataSource } from '../../DatabaseDataModel/IDatabaseDataSource.js';
|
||||
import type { IDataValuePanelOptions, IDataValuePanelProps } from '../../TableViewer/ValuePanel/DataValuePanelService.js';
|
||||
import { useAutoContentType } from './useAutoContentType.js';
|
||||
|
||||
interface UseContentTypeArgs {
|
||||
model: IDatabaseDataModel<IDatabaseDataSource>;
|
||||
currentContentType: string | null;
|
||||
elementKey?: IGridDataKey;
|
||||
formatAction?: IDatabaseDataFormatAction;
|
||||
displayed: Array<ITabInfo<IDataValuePanelProps, IDataValuePanelOptions>>;
|
||||
}
|
||||
|
||||
const DEFAULT_CONTENT_TYPE = 'text/plain';
|
||||
|
||||
export function useContentType({ model, formatAction, currentContentType, elementKey, displayed }: UseContentTypeArgs): string {
|
||||
const autoContentType = useAutoContentType({ displayed, formatAction, model, elementKey });
|
||||
if (displayed.length === 0) {
|
||||
return currentContentType || DEFAULT_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
currentContentType = currentContentType || autoContentType;
|
||||
const hasCurrentTab = currentContentType && displayed.some(tab => tab.key === currentContentType);
|
||||
|
||||
if (!hasCurrentTab) {
|
||||
currentContentType = currentContentType || displayed[0]!.key;
|
||||
}
|
||||
|
||||
return currentContentType || DEFAULT_CONTENT_TYPE;
|
||||
}
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
import { Bootstrap, conditional, Dependency, external, ModuleRegistry, proxy } from '@cloudbeaver/core-di';
|
||||
import { TextValuePresentationBootstrap } from './ValuePanelPresentation/TextValue/TextValuePresentationBootstrap.js';
|
||||
import { TextValuePresentationService } from './ValuePanelPresentation/TextValue/TextValuePresentationService.js';
|
||||
import { ImageValuePresentationBootstrap } from './ValuePanelPresentation/ImageValue/ImageValuePresentationBootstrap.js';
|
||||
import { BooleanValuePresentationBootstrap } from './ValuePanelPresentation/BooleanValue/BooleanValuePresentationBootstrap.js';
|
||||
import { TableViewerStorageService } from './TableViewer/TableViewerStorageService.js';
|
||||
@@ -72,7 +71,6 @@ export default ModuleRegistry.add({
|
||||
.addSingleton(Dependency, proxy(DataViewerSettingsService))
|
||||
.addSingleton(DataPresentationService)
|
||||
.addSingleton(TextValuePresentationBootstrap)
|
||||
.addSingleton(TextValuePresentationService)
|
||||
.addSingleton(ImageValuePresentationBootstrap)
|
||||
.addSingleton(BooleanValuePresentationBootstrap)
|
||||
.addSingleton(TableViewerStorageService)
|
||||
|
||||
Reference in New Issue
Block a user