mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-19 10:36:33 +08:00
dbeaver/pro#9614 add predefined param for connection type (#4454)
* dbeaver/pro#9614 add predefined param for connection type * dbeaver/pro#9614 add connection type selector * dbeaver/pro#9614 make menu indicator more visible * dbeaver/pro#9614 add extra colors * dbeaver/pro#9614 outdate connections * dbeaver/pro#9614 load types in bootstrap phrase * dbeaver/pro#9614 always use useConnectionTypeColor * dbeaver/pro#9614 remove unused import * dbeaver/pro#9614 add useConnectionTypeLoader hook * dbeaver/pro#9614 add default hint * dbeaver/pro#9614 do not wrap arg:item by default * dbeaver/pro#9614 use predefined unset for all types * dbeaver/pro#9614 use common mapped unset color --------- Co-authored-by: Ainur <ainur.iagudin@dbeaver.com> Co-authored-by: Evgenia <139753579+EvgeniaBzzz@users.noreply.github.com>
This commit is contained in:
@@ -664,6 +664,8 @@ type ConnectionType @since(version: "26.1.2") {
|
||||
autoCloseConnections: Boolean!
|
||||
"Auto-close idle connections period in seconds for this connection type"
|
||||
closeIdleConnectionPeriod: Int!
|
||||
"Specifies whether this connection type is system-defined or user-defined. System-defined connection types cannot be deleted."
|
||||
predefined: Boolean!
|
||||
}
|
||||
|
||||
####################################################
|
||||
|
||||
@@ -13,9 +13,10 @@ import { memo } from 'react';
|
||||
interface Props {
|
||||
color: string;
|
||||
isSelected?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ColorIndicator = memo(function ColorIndicator({ color, isSelected }: Props) {
|
||||
export const ColorIndicator = memo(function ColorIndicator({ color, isSelected, className }: Props) {
|
||||
const isLight = ColorConvert(color).isLight();
|
||||
const selectedMark = isLight ? 'dbv-kit-color-picker__color--selected-light' : 'dbv-kit-color-picker__color--selected-dark';
|
||||
|
||||
@@ -24,6 +25,7 @@ export const ColorIndicator = memo(function ColorIndicator({ color, isSelected }
|
||||
className={clsx(
|
||||
'dbv_kit_color-picker__color tw:w-5 tw:h-5 tw:rounded-full tw:border tw:border-(--dbv-kit-color-picker-border-color)',
|
||||
isSelected && selectedMark,
|
||||
className,
|
||||
)}
|
||||
style={{ backgroundColor: color }}
|
||||
/>
|
||||
|
||||
@@ -12,6 +12,6 @@ export function normalizeColorToHex(color: string): string {
|
||||
return ColorConvert(color).hex();
|
||||
}
|
||||
|
||||
export function normalizeColorToRgb(color: string): string {
|
||||
return ColorConvert(color).rgb().string();
|
||||
}
|
||||
export function normalizeColorToRgb(color: string): ReturnType<typeof ColorConvert.rgb> {
|
||||
return ColorConvert(color).rgb();
|
||||
}
|
||||
@@ -26,7 +26,9 @@ export { IconButton, IconButtonBase, type IconButtonProps } from './IconButton/I
|
||||
export { Checkbox, CheckboxBase, type CheckboxProps } from './Checkbox/Checkbox.js';
|
||||
export { CheckboxIndicator, type ICheckboxIndicatorProps } from './Checkbox/CheckboxIndicator.js';
|
||||
export { ColorPicker } from './ColorPicker/ColorPicker.js';
|
||||
export { ColorIndicator } from './ColorPicker/ColorIndicator.js';
|
||||
export { ColorPickerBase, type ColorPickerProps } from './ColorPicker/ColorPickerBase.js';
|
||||
export { normalizeColorToRgb } from './ColorPicker/colorUtils.js';
|
||||
export { Input, InputBase, type InputProps } from './Input/Input.js';
|
||||
export {
|
||||
SearchPanel,
|
||||
|
||||
@@ -14,11 +14,12 @@ import { useObjectRef } from '../../useObjectRef.js';
|
||||
import { useObservableRef } from '../../useObservableRef.js';
|
||||
import { useS } from '../../useS.js';
|
||||
import type { ITreeNodeState } from './ITreeNodeState.js';
|
||||
import style from './TreeNode.module.css';
|
||||
import componentStyle from './TreeNode.module.css';
|
||||
import { type ITreeNodeContext, TreeNodeContext } from './TreeNodeContext.js';
|
||||
|
||||
interface Props extends ITreeNodeState {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
onClick?: (leaf: boolean) => Promise<void> | void;
|
||||
onExpand?: () => Promise<void> | void;
|
||||
@@ -43,12 +44,13 @@ export const TreeNode = observer<Props, HTMLDivElement | null>(
|
||||
externalExpanded,
|
||||
leaf = false,
|
||||
className,
|
||||
style,
|
||||
children,
|
||||
...handlers
|
||||
},
|
||||
ref,
|
||||
) {
|
||||
const styles = useS(style);
|
||||
const styles = useS(componentStyle);
|
||||
const handlersRef = useObjectRef(handlers);
|
||||
|
||||
const nodeContext = useObservableRef<IInnerTreeNodeContext>(
|
||||
@@ -115,7 +117,7 @@ export const TreeNode = observer<Props, HTMLDivElement | null>(
|
||||
);
|
||||
|
||||
return (
|
||||
<div ref={ref} className={s(styles, { node: true }, className)}>
|
||||
<div ref={ref} className={s(styles, { node: true }, className)} style={style}>
|
||||
<TreeNodeContext.Provider value={nodeContext}>{children}</TreeNodeContext.Provider>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -259,3 +259,5 @@ export * from './ObjectPropertyInfo/evaluate.js';
|
||||
export * from './ObjectPropertyInfo/getObjectPropertyDefaults.js';
|
||||
export * from './useVisible.js';
|
||||
export * from './SAVED_VALUE_INDICATOR.js';
|
||||
export * from './FormControls/Field.js';
|
||||
export * from './FormControls/FieldLabel.js';
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
"@cloudbeaver/core-root": "workspace:*",
|
||||
"@cloudbeaver/core-sdk": "workspace:*",
|
||||
"@cloudbeaver/core-settings": "workspace:*",
|
||||
"@cloudbeaver/core-theming": "workspace:*",
|
||||
"@cloudbeaver/core-utils": "workspace:*",
|
||||
"@dbeaver/js-helpers": "workspace:*",
|
||||
"mobx": "^6",
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { CachedMapAllKey, CachedMapResource, resourceKeyList, type ResourceKey } from '@cloudbeaver/core-resource';
|
||||
import { ServerConfigResource } from '@cloudbeaver/core-root';
|
||||
import { GraphQLService, type ConnectionType as ConnectionTypeFragment } from '@cloudbeaver/core-sdk';
|
||||
import { isNotNullDefined } from '@dbeaver/js-helpers';
|
||||
|
||||
import { ConnectionInfoResource, createConnectionParam } from '../ConnectionInfoResource.js';
|
||||
|
||||
export type ConnectionType = ConnectionTypeFragment;
|
||||
|
||||
export const NEW_CONNECTION_TYPE_SYMBOL = Symbol('new-connection-type');
|
||||
export type NewConnectionType = ConnectionType & { [NEW_CONNECTION_TYPE_SYMBOL]: boolean; timestamp: number };
|
||||
|
||||
@injectable(() => [GraphQLService, ConnectionInfoResource, ServerConfigResource])
|
||||
export class ConnectionTypeResource extends CachedMapResource<string, ConnectionType> {
|
||||
constructor(
|
||||
private readonly graphQLService: GraphQLService,
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
serverConfigResource: ServerConfigResource,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.onItemDelete.addHandler(this.handleTypeChanges.bind(this));
|
||||
this.onItemUpdate.addHandler(this.handleTypeChanges.bind(this));
|
||||
this.onDataOutdated.addHandler(this.handleTypeChanges.bind(this));
|
||||
|
||||
this.sync(
|
||||
serverConfigResource,
|
||||
() => {},
|
||||
() => CachedMapAllKey,
|
||||
);
|
||||
}
|
||||
|
||||
protected async loader(originalKey: ResourceKey<string>): Promise<Map<string, ConnectionType>> {
|
||||
const all = this.aliases.isAlias(originalKey, CachedMapAllKey);
|
||||
|
||||
const { types } = await this.graphQLService.sdk.getConnectionTypes();
|
||||
|
||||
const key = resourceKeyList(types.map(type => type.id));
|
||||
if (all) {
|
||||
this.replace(key, types);
|
||||
} else {
|
||||
this.set(key, types);
|
||||
}
|
||||
|
||||
return this.data;
|
||||
}
|
||||
|
||||
compare(connectionTypeA: ConnectionType, connectionTypeB: ConnectionType): number {
|
||||
if (connectionTypeA.predefined !== connectionTypeB.predefined) {
|
||||
return connectionTypeA.predefined ? -1 : 1;
|
||||
}
|
||||
|
||||
return connectionTypeA.name.localeCompare(connectionTypeB.name);
|
||||
}
|
||||
|
||||
cleanNewFlags(): void {
|
||||
for (const connection of this.data.values()) {
|
||||
(connection as NewConnectionType)[NEW_CONNECTION_TYPE_SYMBOL] = false;
|
||||
}
|
||||
}
|
||||
|
||||
async refreshAll(): Promise<Map<string, ConnectionType>> {
|
||||
await this.refresh(CachedMapAllKey);
|
||||
return this.data;
|
||||
}
|
||||
|
||||
protected override validateKey(key: string): boolean {
|
||||
return typeof key === 'string';
|
||||
}
|
||||
|
||||
private handleTypeChanges(key: ResourceKey<string>) {
|
||||
const types = this.get(key);
|
||||
|
||||
if (!types) {
|
||||
return;
|
||||
}
|
||||
|
||||
const typeIds: string[] = [];
|
||||
|
||||
if (Array.isArray(types)) {
|
||||
typeIds.push(...types.filter(isNotNullDefined).map(type => type.id));
|
||||
} else {
|
||||
typeIds.push(types.id);
|
||||
}
|
||||
|
||||
const connections = this.connectionInfoResource.values.filter(connection => typeIds.includes(connection.connectionType));
|
||||
|
||||
if (!connections.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = resourceKeyList(connections.map(connection => createConnectionParam(connection.projectId, connection.id)));
|
||||
this.connectionInfoResource.markOutdated(result);
|
||||
}
|
||||
}
|
||||
|
||||
function isNewConnectionType(connection: ConnectionType | NewConnectionType): connection is NewConnectionType {
|
||||
return (connection as NewConnectionType)[NEW_CONNECTION_TYPE_SYMBOL];
|
||||
}
|
||||
|
||||
export function compareNewConnectionTypes(a: ConnectionType, b: ConnectionType): number {
|
||||
if (isNewConnectionType(a) && isNewConnectionType(b)) {
|
||||
return b.timestamp - a.timestamp;
|
||||
}
|
||||
|
||||
if (isNewConnectionType(b)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isNewConnectionType(a)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
export function mapColorValue(value: string): string {
|
||||
return `rgb(${value})`;
|
||||
}
|
||||
|
||||
export const PREDEFINED_UNSET_COLOR = '255,255,255';
|
||||
export const MAPPED_PREDEFINED_UNSET_COLOR = `rgba(${PREDEFINED_UNSET_COLOR}, 0)`;
|
||||
export const DEFAULT_TYPE_ID = 'dev';
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { ThemeService } from '@cloudbeaver/core-theming';
|
||||
|
||||
import { ConnectionTypeResource, mapColorValue, PREDEFINED_UNSET_COLOR } from './ConnectionTypeResource.js';
|
||||
import { ConnectionInfoResource } from '../ConnectionInfoResource.js';
|
||||
import type { IConnectionInfoParams } from '../CONNECTION_INFO_PARAM_SCHEMA.js';
|
||||
|
||||
@injectable(() => [ConnectionTypeResource, ConnectionInfoResource, ThemeService])
|
||||
export class ConnectionTypeService {
|
||||
constructor(
|
||||
private readonly connectionTypeResource: ConnectionTypeResource,
|
||||
private readonly connectionInfoResource: ConnectionInfoResource,
|
||||
private readonly themeService: ThemeService,
|
||||
) {}
|
||||
|
||||
getConnectionTypeColor(connectionKey: IConnectionInfoParams): string | undefined {
|
||||
const connection = this.connectionInfoResource.get(connectionKey);
|
||||
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
|
||||
return this.getTypeColor(connection.connectionType);
|
||||
}
|
||||
|
||||
getTypeColor(typeId: string): string | undefined {
|
||||
const theme = this.themeService.currentTheme?.type;
|
||||
const connectionType = this.connectionTypeResource.get(typeId);
|
||||
|
||||
if (!connectionType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let color = connectionType.colorLight;
|
||||
|
||||
if (connectionType.colorDark && theme === 'dark') {
|
||||
color = connectionType.colorDark;
|
||||
}
|
||||
|
||||
if (color === PREDEFINED_UNSET_COLOR) {
|
||||
return;
|
||||
}
|
||||
|
||||
return mapColorValue(color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { useService } from '@cloudbeaver/core-di';
|
||||
|
||||
import type { IConnectionInfoParams } from '../CONNECTION_INFO_PARAM_SCHEMA.js';
|
||||
import { ConnectionTypeService } from './ConnectionTypeService.js';
|
||||
|
||||
export function useConnectionTypeColor(connectionKey: IConnectionInfoParams | undefined): string | undefined {
|
||||
const connectionTypeService = useService(ConnectionTypeService);
|
||||
|
||||
if (!connectionKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
return connectionTypeService.getConnectionTypeColor(connectionKey);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { useResource } from '@cloudbeaver/core-blocks';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
|
||||
import { UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
|
||||
import { ConnectionTypeResource } from './ConnectionTypeResource.js';
|
||||
import { ConnectionInfoActiveProjectKey, ConnectionInfoResource } from '../ConnectionInfoResource.js';
|
||||
|
||||
/**
|
||||
* Preloads connection types once at a higher level — avoids per-node or per-connection useResource
|
||||
* subscriptions, which cause perfomance issues with 500+ entities. Used alongside useConnectionTypeColor.
|
||||
*/
|
||||
export function useConnectionTypeLoader(): void {
|
||||
const userInfoResource = useResource(useConnectionTypeLoader, UserInfoResource, undefined);
|
||||
|
||||
useResource(useConnectionTypeLoader, ConnectionInfoResource, ConnectionInfoActiveProjectKey, { active: userInfoResource.resource.hasAccess() });
|
||||
useResource(useConnectionTypeLoader, ConnectionTypeResource, CachedMapAllKey);
|
||||
}
|
||||
@@ -63,3 +63,8 @@ export * from './useDBDriver.js';
|
||||
export * from './USER_NAME_PROPERTY_ID.js';
|
||||
export * from './parseConnectionKey.js';
|
||||
export * from './DBDriverExpertSettingsResource.js';
|
||||
|
||||
export * from './ConnectionType/ConnectionTypeResource.js';
|
||||
export * from './ConnectionType/ConnectionTypeService.js';
|
||||
export * from './ConnectionType/useConnectionTypeColor.js';
|
||||
export * from './ConnectionType/useConnectionTypeLoader.js';
|
||||
|
||||
@@ -32,6 +32,8 @@ import { ConnectionFolderEventHandler } from './ConnectionFolderEventHandler.js'
|
||||
import { ConnectionExecutionContextResource } from './ConnectionExecutionContext/ConnectionExecutionContextResource.js';
|
||||
import { ConnectionDialectResource } from './ConnectionDialectResource.js';
|
||||
import { DBDriverExpertSettingsResource } from './DBDriverExpertSettingsResource.js';
|
||||
import { ConnectionTypeService } from './ConnectionType/ConnectionTypeService.js';
|
||||
import { ConnectionTypeResource } from './ConnectionType/ConnectionTypeResource.js';
|
||||
|
||||
export default ModuleRegistry.add({
|
||||
name: '@cloudbeaver/core-connections',
|
||||
@@ -57,6 +59,7 @@ export default ModuleRegistry.add({
|
||||
.addSingleton(Dependency, proxy(ConnectionFolderResource))
|
||||
.addSingleton(Dependency, proxy(ConnectionExecutionContextResource))
|
||||
.addSingleton(Dependency, proxy(DBDriverExpertSettingsResource))
|
||||
.addSingleton(Dependency, proxy(ConnectionTypeResource))
|
||||
.addSingleton(ConnectionDialectResource)
|
||||
.addSingleton(NavNodeExtensionsService)
|
||||
.addSingleton(DBDriverResource)
|
||||
@@ -80,6 +83,8 @@ export default ModuleRegistry.add({
|
||||
.addSingleton(ConnectionFolderResource)
|
||||
.addSingleton(ConnectionExecutionContextService)
|
||||
.addSingleton(ConnectionFolderEventHandler)
|
||||
.addSingleton(ConnectionExecutionContextResource);
|
||||
.addSingleton(ConnectionExecutionContextResource)
|
||||
.addSingleton(ConnectionTypeResource)
|
||||
.addSingleton(ConnectionTypeService);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
{
|
||||
"path": "../core-settings"
|
||||
},
|
||||
{
|
||||
"path": "../core-theming"
|
||||
},
|
||||
{
|
||||
"path": "../core-utils"
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@ export default [
|
||||
['name', 'en'],
|
||||
['ui_rename_taken_or_invalid', 'This name is unavailable or invalid'],
|
||||
['ui_tag_new', 'New'],
|
||||
['ui_theme', 'Theme'],
|
||||
['ui_light_theme', 'Light'],
|
||||
['ui_dark_theme', 'Dark'],
|
||||
['ui_system_theme', 'Device'],
|
||||
@@ -149,7 +150,7 @@ export default [
|
||||
['ui_project', 'Project'],
|
||||
['ui_type', 'Type'],
|
||||
['ui_field_is_required', 'Please fill in this field'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete "{arg:item}". Are you sure?'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete {arg:item}. Are you sure?'],
|
||||
['ui_not_selected', 'Not selected'],
|
||||
['ui_reset', 'Reset'],
|
||||
['ui_documentaion', 'Documentation'],
|
||||
@@ -157,6 +158,7 @@ export default [
|
||||
['ui_allow', 'Allow'],
|
||||
['ui_decline', 'Decline'],
|
||||
['ui_declined', 'Declined'],
|
||||
['ui_default', 'Default'],
|
||||
|
||||
['root_permission_denied', "You don't have permissions"],
|
||||
['root_permission_no_permission', "You don't have permission for this action"],
|
||||
|
||||
@@ -143,7 +143,7 @@ export default [
|
||||
['ui_project', 'Project'],
|
||||
['ui_type', 'Type'],
|
||||
['ui_field_is_required', 'Please fill in this field'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete "{arg:item}". Are you sure?'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete {arg:item}. Are you sure?'],
|
||||
['ui_not_selected', 'Not selected'],
|
||||
['ui_reset', 'Reset'],
|
||||
['ui_documentaion', 'Documentation'],
|
||||
|
||||
@@ -140,7 +140,7 @@ export default [
|
||||
['ui_project', 'Project'],
|
||||
['ui_type', 'Type'],
|
||||
['ui_field_is_required', 'Please fill in this field'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete "{arg:item}". Are you sure?'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete {arg:item}. Are you sure?'],
|
||||
['ui_not_selected', 'Not selected'],
|
||||
['ui_reset', 'Reset'],
|
||||
['ui_documentaion', 'Documentation'],
|
||||
|
||||
@@ -2,6 +2,7 @@ export default [
|
||||
['name', 'ru'],
|
||||
['ui_rename_taken_or_invalid', 'Имя занято или недопустимо'],
|
||||
['ui_tag_new', 'Новый'],
|
||||
['ui_theme', 'Тема'],
|
||||
['ui_light_theme', 'Светлая'],
|
||||
['ui_dark_theme', 'Темная'],
|
||||
['ui_system_theme', 'Устройство'],
|
||||
@@ -154,6 +155,7 @@ export default [
|
||||
['ui_allow', 'Разрешить'],
|
||||
['ui_decline', 'Отклонить'],
|
||||
['ui_declined', 'Отклонено'],
|
||||
['ui_default', 'По умолчанию'],
|
||||
|
||||
['root_permission_denied', 'Отказано в доступе'],
|
||||
['root_permission_no_permission', 'У вас нет разрешения на это действие'],
|
||||
|
||||
@@ -146,7 +146,7 @@ export default [
|
||||
['ui_project', 'Project'],
|
||||
['ui_type', 'Type'],
|
||||
['ui_field_is_required', 'Please fill in this field'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete "{arg:item}". Are you sure?'],
|
||||
['ui_delete_confirmation_message', 'You are about to delete {arg:item}. Are you sure?'],
|
||||
['ui_not_selected', 'Not selected'],
|
||||
['ui_reset', 'Reset'],
|
||||
['ui_documentaion', '文档'],
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
query getConnectionTypes {
|
||||
types: listConnectionTypes {
|
||||
...ConnectionType
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fragment ConnectionType on ConnectionType {
|
||||
id
|
||||
name
|
||||
description
|
||||
colorLight
|
||||
colorDark
|
||||
|
||||
autocommit
|
||||
confirmExecute
|
||||
confirmDataChange
|
||||
smartCommit
|
||||
smartCommitRecover
|
||||
autoCloseTransactions
|
||||
closeIdleTransactionPeriod
|
||||
autoCloseConnections
|
||||
closeIdleConnectionPeriod
|
||||
predefined
|
||||
}
|
||||
@@ -13,4 +13,5 @@ fragment DatabaseConnection on ConnectionInfo {
|
||||
canViewSettings
|
||||
canEdit
|
||||
canDelete
|
||||
connectionType
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
}
|
||||
|
||||
&:not(:global([aria-selected='true'])) {
|
||||
background-color: transparent !important;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,19 +13,19 @@ import { getComputed, s, useS, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
|
||||
import { TabContext } from '../TabContext.js';
|
||||
import { useTabDragAndDrop } from '../useTabDragAndDrop.js';
|
||||
import style from './Tab.module.css';
|
||||
import componentStyles from './Tab.module.css';
|
||||
import { TabActions } from './TabActions.js';
|
||||
import type { TabProps } from './TabProps.js';
|
||||
import { useTab } from './useTab.js';
|
||||
|
||||
export const Tab = observer<TabProps>(function Tab({ after, ...props }) {
|
||||
const translate = useTranslate();
|
||||
const { tabId, title, disabled, className, children, onOpen, onClose, onClick } = props;
|
||||
const { tabId, title, disabled, className, style, children, onOpen, onClose, onClick } = props;
|
||||
const ref = useRef<HTMLButtonElement>(null);
|
||||
const tabContext = useMemo(() => ({ tabId }), [tabId]);
|
||||
const tab = useTab(tabId, onOpen, onClose, onClick);
|
||||
const info = tab.getInfo();
|
||||
const styles = useS(style);
|
||||
const styles = useS(componentStyles);
|
||||
const canClose = getComputed(() => !!onClose || (tab.closable && tab.state.closable));
|
||||
|
||||
const {
|
||||
@@ -76,6 +76,7 @@ export const Tab = observer<TabProps>(function Tab({ after, ...props }) {
|
||||
title={translate(title ?? info?.title)}
|
||||
id={tabId}
|
||||
className={s(styles, { tab: true }, className)}
|
||||
style={style}
|
||||
disabled={disabled}
|
||||
tabbable
|
||||
onClick={tab.handleOpen}
|
||||
|
||||
@@ -18,6 +18,7 @@ export type TabProps = PropsWithChildren<{
|
||||
selected?: boolean;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
after?: React.ReactElement;
|
||||
onOpen?: (tab: ITabData<any>) => void;
|
||||
onClose?: (tab: ITabData<any>) => void;
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
"@cloudbeaver/plugin-top-app-bar": "workspace:*",
|
||||
"@dbeaver/jdbc-uri-parser": "workspace:*",
|
||||
"@dbeaver/js-helpers": "workspace:*",
|
||||
"@dbeaver/ui-kit": "workspace:*",
|
||||
"mobx": "^6",
|
||||
"mobx-react-lite": "^4",
|
||||
"react": "^19",
|
||||
|
||||
@@ -37,4 +37,5 @@ export const CONNECTION_CONFIG_SCHEMA = schema.object({
|
||||
url: schema.string().optional(),
|
||||
userName: schema.string().optional(),
|
||||
userPassword: schema.string().optional(),
|
||||
connectionType: schema.string().optional(),
|
||||
});
|
||||
|
||||
+5
-1
@@ -58,6 +58,7 @@ const defaultStateGetter = (connectionId?: string, credentials?: Record<string,
|
||||
expertSettingsValues: {},
|
||||
networkHandlersConfig: [],
|
||||
providerProperties: {},
|
||||
connectionType: 'dev',
|
||||
}) as IConnectionFormOptionsState;
|
||||
|
||||
export class ConnectionFormOptionsPart extends FormPart<IConnectionFormOptionsState, IConnectionFormState> {
|
||||
@@ -200,10 +201,11 @@ export class ConnectionFormOptionsPart extends FormPart<IConnectionFormOptionsSt
|
||||
return;
|
||||
}
|
||||
|
||||
const [authPropertiesInfo, customOptionsInfo, providerPropertiesInfo] = await Promise.all([
|
||||
const [authPropertiesInfo, customOptionsInfo, providerPropertiesInfo, connection] = await Promise.all([
|
||||
this.connectionInfoAuthPropertiesResource.load(this.connectionKey),
|
||||
this.connectionInfoCustomOptionsResource.load(this.connectionKey),
|
||||
this.connectionInfoProviderPropertiesResource.load(this.connectionKey),
|
||||
this.connectionInfoResource.load(this.connectionKey),
|
||||
]);
|
||||
|
||||
const config: ConnectionConfig = defaultStateGetter();
|
||||
@@ -223,6 +225,8 @@ export class ConnectionFormOptionsPart extends FormPart<IConnectionFormOptionsSt
|
||||
config.url = customOptionsInfo.url;
|
||||
config.folder = customOptionsInfo.folder;
|
||||
|
||||
config.connectionType = connection.connectionType;
|
||||
|
||||
config.authModelId = authPropertiesInfo.authModel;
|
||||
config.saveCredentials = authPropertiesInfo.credentialsSaved;
|
||||
config.sharedCredentials = authPropertiesInfo.sharedCredentials;
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2026 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 { Container, Group, GroupTitle, Select, useResource, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { CachedMapAllKey } from '@cloudbeaver/core-resource';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { isNotNullDefined } from '@dbeaver/js-helpers';
|
||||
import { ColorIndicator } from '@dbeaver/ui-kit';
|
||||
import { ConnectionTypeResource, ConnectionTypeService, DEFAULT_TYPE_ID, MAPPED_PREDEFINED_UNSET_COLOR } from '@cloudbeaver/core-connections';
|
||||
import type { ConnectionConfig } from '@cloudbeaver/core-sdk';
|
||||
|
||||
interface Props {
|
||||
config: ConnectionConfig;
|
||||
}
|
||||
|
||||
export const ConnectionTypeForm = observer<Props>(function ConnectionTypeForm({ config }) {
|
||||
const translate = useTranslate();
|
||||
const connectionTypeService = useService(ConnectionTypeService);
|
||||
|
||||
const connectionTypeResource = useResource(ConnectionTypeForm, ConnectionTypeResource, CachedMapAllKey);
|
||||
const types = connectionTypeResource.data.filter(isNotNullDefined);
|
||||
|
||||
return (
|
||||
<Group form gap>
|
||||
<GroupTitle>{translate('plugin_connections_connection_type_label')}</GroupTitle>
|
||||
<Container gap dense>
|
||||
<Select
|
||||
items={types}
|
||||
name="connectionType"
|
||||
state={config}
|
||||
keySelector={t => t.id}
|
||||
valueSelector={t => (t.id === DEFAULT_TYPE_ID ? `${t.name} (${translate('ui_default')})` : t.name)}
|
||||
iconSelector={t => {
|
||||
const color = connectionTypeService.getTypeColor(t.id);
|
||||
return <ColorIndicator className="tw:w-3.5! tw:h-3.5!" color={color ?? MAPPED_PREDEFINED_UNSET_COLOR} />;
|
||||
}}
|
||||
/>
|
||||
</Container>
|
||||
</Group>
|
||||
);
|
||||
});
|
||||
@@ -64,6 +64,7 @@ import { ProviderPropertiesForm } from './ProviderPropertiesForm.js';
|
||||
import { getConnectionFormOptionsPart } from './getConnectionFormOptionsPart.js';
|
||||
import type { IConnectionFormProps } from '../IConnectionFormState.js';
|
||||
import { ConnectionFormService } from '../ConnectionFormService.js';
|
||||
import { ConnectionTypeForm } from './ConnectionTypeForm.js';
|
||||
|
||||
const PROFILE_AUTH_MODEL_ID = 'profile';
|
||||
|
||||
@@ -309,6 +310,7 @@ export const Options: TabContainerPanelComponent<IConnectionFormProps> = observe
|
||||
)}
|
||||
</Group>
|
||||
)}
|
||||
<ConnectionTypeForm config={optionsPart.state} />
|
||||
<Placeholder container={connectionFormService.connectionContainer} formState={formState} />
|
||||
</Container>
|
||||
<Container medium gap>
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 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 { ConnectionTypeResource } from '@cloudbeaver/core-connections';
|
||||
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
|
||||
|
||||
@injectable()
|
||||
@injectable(() => [ConnectionTypeResource])
|
||||
export class PluginBootstrap extends Bootstrap {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
override async load(): Promise<void> {}
|
||||
}
|
||||
|
||||
@@ -44,4 +44,6 @@ export default [
|
||||
['plugin_connections_connection_client_version', 'Client version: {arg:version} \n'],
|
||||
['plugin_connections_connection_server_version', 'Server version: {arg:version} \n'],
|
||||
['plugin_connections_connection_connection_time', 'Connection time: {arg:time} \n'],
|
||||
|
||||
['plugin_connections_connection_type_label', 'Connection type'],
|
||||
];
|
||||
|
||||
@@ -47,4 +47,6 @@ export default [
|
||||
['plugin_connections_connection_client_version', 'Версия клиента: {arg:version} \n'],
|
||||
['plugin_connections_connection_server_version', 'Версия сервера: {arg:version} \n'],
|
||||
['plugin_connections_connection_connection_time', 'Время подключения: {arg:time} \n'],
|
||||
|
||||
['plugin_connections_connection_type_label', 'Тип подключения'],
|
||||
];
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "../../common-react/@dbeaver/ui-kit"
|
||||
},
|
||||
{
|
||||
"path": "../../common-typescript/@dbeaver/jdbc-uri-parser"
|
||||
},
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { ResultDataFormat } from '@cloudbeaver/core-sdk';
|
||||
import { CaptureView } from '@cloudbeaver/core-view';
|
||||
import { createConnectionParam, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
|
||||
import { type IDatabaseDataOptions } from '../DatabaseDataModel/IDatabaseDataOptions.js';
|
||||
import { DataPresentationService, DataPresentationType } from '../DataPresentationService.js';
|
||||
@@ -44,6 +45,7 @@ import { TableToolsPanel } from './TableToolsPanel.js';
|
||||
import style from './TableViewer.module.css';
|
||||
import { TableViewerStorageService } from './TableViewerStorageService.js';
|
||||
import { IDatabaseDataConstraintAction } from '../DatabaseDataModel/Actions/IDatabaseDataConstraintAction.js';
|
||||
import { ResultSetDataSource } from '../ResultSet/ResultSetDataSource.js';
|
||||
|
||||
export interface TableViewerProps {
|
||||
tableId: string;
|
||||
@@ -182,6 +184,10 @@ export const TableViewer = observer<TableViewerProps, HTMLDivElement>(
|
||||
// }
|
||||
// }, [dataFormat]);
|
||||
|
||||
const context = dataModel?.source instanceof ResultSetDataSource ? dataModel.source.executionContext?.context : undefined;
|
||||
const connectionKey = context ? createConnectionParam(context.projectId, context.connectionId) : undefined;
|
||||
const typeColor = useConnectionTypeColor(connectionKey);
|
||||
|
||||
if (!dataModel) {
|
||||
return <TextPlaceholder>{translate('plugin_data_viewer_no_available_presentation')}</TextPlaceholder>;
|
||||
}
|
||||
@@ -208,7 +214,7 @@ export const TableViewer = observer<TableViewerProps, HTMLDivElement>(
|
||||
|
||||
return (
|
||||
<CaptureView className={s(styles, { captureView: true })} view={dataViewerView}>
|
||||
<div ref={mergedRef} tabIndex={0} className={s(styles, { tableViewer: true }, className)}>
|
||||
<div ref={mergedRef} tabIndex={0} className={s(styles, { tableViewer: true }, className)} style={{ background: typeColor }}>
|
||||
<div className={s(styles, { tableContent: true })}>
|
||||
{!isStatistics && (
|
||||
<TablePresentationBar
|
||||
@@ -292,7 +298,14 @@ export const TableViewer = observer<TableViewerProps, HTMLDivElement>(
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<TableFooter model={dataModel} resultIndex={resultIndex} simple={simple} tabIndex={0} data-presentation-tools />
|
||||
<TableFooter
|
||||
style={{ background: typeColor }}
|
||||
model={dataModel}
|
||||
resultIndex={resultIndex}
|
||||
simple={simple}
|
||||
tabIndex={0}
|
||||
data-presentation-tools
|
||||
/>
|
||||
</div>
|
||||
</CaptureView>
|
||||
);
|
||||
|
||||
+6
-1
@@ -1,18 +1,23 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
*/
|
||||
|
||||
.connectionIcon {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.connectionImageWithMask {
|
||||
border-radius: var(--theme-form-element-radius);
|
||||
|
||||
&.small {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+6
-2
@@ -1,25 +1,28 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 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 { useDeferredValue } from 'react';
|
||||
|
||||
import { s, useS, useVisible } from '@cloudbeaver/core-blocks';
|
||||
import { useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
import { isNotNullDefined } from '@dbeaver/js-helpers';
|
||||
|
||||
import styles from './ConnectionIcon.module.css';
|
||||
import ConnectionImageWithMaskSvgBackgroundStyles from './ConnectionImageWithMask.module.css';
|
||||
import { ConnectionIconLazyPart, type ConnectionIconProps } from './ConnectionIconLazyPart.js';
|
||||
import { useDeferredValue } from 'react';
|
||||
|
||||
export const ConnectionIcon = observer<ConnectionIconProps>(function ConnectionIcon({ className, connectionKey, ...props }) {
|
||||
const style = useS(styles, ConnectionImageWithMaskSvgBackgroundStyles);
|
||||
const { isVisible, setRef } = useVisible();
|
||||
|
||||
const deferredIsVisible = useDeferredValue(isVisible);
|
||||
const typeColor = useConnectionTypeColor(connectionKey ?? undefined);
|
||||
|
||||
if (!isNotNullDefined(connectionKey)) {
|
||||
return null;
|
||||
@@ -27,6 +30,7 @@ export const ConnectionIcon = observer<ConnectionIconProps>(function ConnectionI
|
||||
|
||||
return (
|
||||
<div ref={setRef} className={s(style, { connectionIcon: true }, className)}>
|
||||
{typeColor && <div className="tw:h-5 tw:w-1 tw:mr-1 tw:rounded-xs" style={{ background: typeColor }} />}
|
||||
{deferredIsVisible && <ConnectionIconLazyPart connectionKey={connectionKey} {...props} />}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
"@cloudbeaver/core-app": "workspace:*",
|
||||
"@cloudbeaver/core-authentication": "workspace:*",
|
||||
"@cloudbeaver/core-blocks": "workspace:*",
|
||||
"@cloudbeaver/core-connections": "workspace:*",
|
||||
"@cloudbeaver/core-di": "workspace:*",
|
||||
"@cloudbeaver/core-events": "workspace:*",
|
||||
"@cloudbeaver/core-executor": "workspace:*",
|
||||
|
||||
+9
-1
@@ -14,6 +14,7 @@ import { Loader, SContext, type StyleRegistry, useExecutor } from '@cloudbeaver/
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { type ITabData, TabList, TabPanel, TabsState, TabStyles } from '@cloudbeaver/core-ui';
|
||||
import { CaptureView } from '@cloudbeaver/core-view';
|
||||
import { useConnectionTypeLoader } from '@cloudbeaver/core-connections';
|
||||
import { clsx } from '@dbeaver/ui-kit';
|
||||
|
||||
import { NavigationTabsService } from '../NavigationTabsService.js';
|
||||
@@ -48,6 +49,8 @@ export const NavigationTabsBar = observer<Props>(function NavigationTabsBar({ cl
|
||||
const handleSelect = useCallback((tabId: string) => navigation.selectTab(tabId), [navigation]);
|
||||
const handleClose = useCallback((tabId: string) => navigation.closeTab(tabId), [navigation]);
|
||||
|
||||
useConnectionTypeLoader();
|
||||
|
||||
function unloadTabs() {
|
||||
navigation.unloadTabs();
|
||||
}
|
||||
@@ -107,7 +110,12 @@ export const NavigationTabsBar = observer<Props>(function NavigationTabsBar({ cl
|
||||
onReorder={handleReorder}
|
||||
>
|
||||
<div className="tw:outline-none tw:flex-1 tw:flex tw:flex-col tw:max-w-full">
|
||||
<TabList className={clsx("tw:overflow-auto tw:max-w-full theme-background-secondary theme-text-on-secondary", navigationSettings.hasMultipleRows && 'tw:flex-wrap')}>
|
||||
<TabList
|
||||
className={clsx(
|
||||
'tw:overflow-auto tw:max-w-full theme-background-secondary theme-text-on-secondary',
|
||||
navigationSettings.hasMultipleRows && 'tw:flex-wrap',
|
||||
)}
|
||||
>
|
||||
<SContext registry={tabsRegistry}>
|
||||
{navigation.tabIdList.map(tabId => (
|
||||
<TabHandlerTab key={tabId} tabId={tabId} onSelect={handleSelect} onClose={handleClose} />
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
{
|
||||
"path": "../core-cli"
|
||||
},
|
||||
{
|
||||
"path": "../core-connections"
|
||||
},
|
||||
{
|
||||
"path": "../core-di"
|
||||
},
|
||||
|
||||
+5
@@ -26,6 +26,7 @@ import {
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events';
|
||||
import { EObjectFeature, NavNodeInfoResource, NavTreeResource } from '@cloudbeaver/core-navigation-tree';
|
||||
import { createConnectionParam, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
|
||||
import type { NavTreeControlComponent, NavTreeControlProps } from '../ElementsTree/NavigationNodeComponent.js';
|
||||
import style from '../ElementsTree/NavigationTreeNode/NavigationNode/NavigationNodeControl.module.css';
|
||||
@@ -74,10 +75,14 @@ export const ConnectionNavNodeControl: NavTreeControlComponent = observer<NavTre
|
||||
tooltip += `\n${translate('ui_type')}: ${translate('core_connections_connection_temporary')}`;
|
||||
}
|
||||
|
||||
const key = node.projectId && node.objectId ? createConnectionParam(node.projectId, node.objectId) : undefined;
|
||||
const typeColor = useConnectionTypeColor(key);
|
||||
|
||||
return (
|
||||
<TreeNodeControl
|
||||
ref={mergedRef}
|
||||
className={s(styles, { treeNodeControl: true, dragging: !!dndElement }, className)}
|
||||
style={{ background: typeColor }}
|
||||
onClick={onClick}
|
||||
onContextMenu={handleContextMenuOpen}
|
||||
>
|
||||
|
||||
+11
-3
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -8,9 +8,10 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { Translate, TreeNodeNestedMessage } from '@cloudbeaver/core-blocks';
|
||||
import { NAV_NODE_TYPE_CONNECTION } from '@cloudbeaver/core-connections';
|
||||
import { createConnectionParam, NAV_NODE_TYPE_CONNECTION, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NavNodeInfoResource } from '@cloudbeaver/core-navigation-tree';
|
||||
import { clsx } from '@dbeaver/ui-kit';
|
||||
|
||||
import type { NavigationNodeRendererComponent } from '../ElementsTree/NavigationNodeComponent.js';
|
||||
import { NavigationNodeRendererLoader } from '../ElementsTree/NavigationTreeNode/NavigationNodeRendererLoader.js';
|
||||
@@ -40,6 +41,9 @@ const ConnectionRenderer: NavigationNodeRendererComponent = observer(function Ma
|
||||
const navNodeInfoResource = useService(NavNodeInfoResource);
|
||||
const node = navNodeInfoResource.get(nodeId);
|
||||
|
||||
const connectionKey = node?.projectId && node.objectId ? createConnectionParam(node.projectId, node.objectId) : undefined;
|
||||
const typeColor = useConnectionTypeColor(connectionKey);
|
||||
|
||||
if (!node) {
|
||||
return (
|
||||
<TreeNodeNestedMessage>
|
||||
@@ -54,7 +58,11 @@ const ConnectionRenderer: NavigationNodeRendererComponent = observer(function Ma
|
||||
path={path}
|
||||
expanded={expanded}
|
||||
dragging={dragging}
|
||||
className={className}
|
||||
style={typeColor ? ({ ['--connection-type-color']: typeColor } as React.CSSProperties) : undefined}
|
||||
className={clsx(
|
||||
typeColor && 'tw:[&_[data-tree-node-control]]:border-l-2 tw:[&_[data-tree-node-control]]:border-l-[var(--connection-type-color)]',
|
||||
className,
|
||||
)}
|
||||
control={ConnectionNavNodeControl}
|
||||
component={component}
|
||||
/>
|
||||
|
||||
+4
@@ -18,6 +18,7 @@ export type NavTreeNodeComponent = React.FC<{
|
||||
expanded?: boolean;
|
||||
big?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}>;
|
||||
|
||||
export type NavTreeControlProps = {
|
||||
@@ -27,6 +28,7 @@ export type NavTreeControlProps = {
|
||||
dndPlaceholder?: boolean;
|
||||
expanded?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
onClick?: (event: React.MouseEvent<HTMLDivElement>) => void;
|
||||
};
|
||||
|
||||
@@ -40,6 +42,7 @@ export type NavigationNodeComponent = React.FC<{
|
||||
dragging?: boolean;
|
||||
expanded?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}>;
|
||||
|
||||
export type NavigationNodeRendererComponent = React.FC<{
|
||||
@@ -49,4 +52,5 @@ export type NavigationNodeRendererComponent = React.FC<{
|
||||
expanded?: boolean;
|
||||
dragging?: boolean;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}>;
|
||||
|
||||
+4
-2
@@ -16,7 +16,7 @@ import { useDNDData } from '@cloudbeaver/core-ui';
|
||||
|
||||
import { useNavTreeDropBox } from '../../useNavTreeDropBox.js';
|
||||
import type { NavigationNodeComponent } from '../NavigationNodeComponent.js';
|
||||
import style from './NavigationNode.module.css';
|
||||
import componentStyle from './NavigationNode.module.css';
|
||||
import { DATA_ATTRIBUTE_NODE_EDITING } from './NavigationNode/DATA_ATTRIBUTE_NODE_EDITING.js';
|
||||
import { NavigationNodeNested } from './NavigationNode/NavigationNodeNested.js';
|
||||
import { NavigationNodeControlRenderer } from './NavigationNodeControlRenderer.js';
|
||||
@@ -29,8 +29,9 @@ export const NavigationNode: NavigationNodeComponent = observer(function Navigat
|
||||
control: externalControl,
|
||||
expanded: externalExpanded,
|
||||
className,
|
||||
style,
|
||||
}) {
|
||||
const styles = useS(style);
|
||||
const styles = useS(componentStyle);
|
||||
const navNodeManagerService = useService(NavNodeManagerService);
|
||||
const navNode = useNavigationNode(node, path);
|
||||
const context = useDataContext();
|
||||
@@ -96,6 +97,7 @@ export const NavigationNode: NavigationNodeComponent = observer(function Navigat
|
||||
externalExpanded={externalExpanded}
|
||||
leaf={navNode.leaf}
|
||||
className={s(styles, { treeNode: true, hovered: hasNodes, expanded: externalExpanded ?? navNode.expanded }, className)}
|
||||
style={style}
|
||||
onExpand={navNode.expand}
|
||||
onClick={navNode.click}
|
||||
onOpen={navNode.open}
|
||||
|
||||
+1
-1
@@ -26,5 +26,5 @@
|
||||
.icon {
|
||||
width: 16px;
|
||||
height: 10px;
|
||||
fill: #dedede;
|
||||
fill: #4d4b4bbd;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useService } from '@cloudbeaver/core-di';
|
||||
import { NavNodeInfoResource, NavTreeResource, ProjectsNavNodeService, ROOT_NODE_PATH } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ProjectsService } from '@cloudbeaver/core-projects';
|
||||
import { CaptureView } from '@cloudbeaver/core-view';
|
||||
import { useConnectionTypeLoader } from '@cloudbeaver/core-connections';
|
||||
|
||||
import { ElementsTreeToolsStyles } from '../index.js';
|
||||
import { NavNodeViewService } from '../NodesManager/NavNodeView/NavNodeViewService.js';
|
||||
@@ -61,6 +62,8 @@ export const NavigationTree = observer(function NavigationTree() {
|
||||
const navTreeResource = useService(NavTreeResource);
|
||||
const navNodeViewService = useService(NavNodeViewService);
|
||||
|
||||
useConnectionTypeLoader();
|
||||
|
||||
const root = ROOT_NODE_PATH;
|
||||
const { handleOpen, handleSelect, handleSelectReset } = useNavigationTree();
|
||||
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -49,7 +49,7 @@ export const VirtualFolderPanel: NavNodeTransformViewComponent = observer(functi
|
||||
<TextPlaceholder>{translate('plugin_object_viewer_table_no_items')}</TextPlaceholder>
|
||||
) : (
|
||||
<div className={classes['tabWrapper']}>
|
||||
<TableLoader objects={objects} hasNextPage={pagination?.hasNextPage ?? false} loadMore={pagination.loadMore} />
|
||||
<TableLoader objects={objects} objectId={nodeId} hasNextPage={pagination?.hasNextPage ?? false} loadMore={pagination.loadMore} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -115,13 +115,15 @@ export const ObjectFolders = observer<IProps>(function ObjectFolders({ tab }) {
|
||||
return folders.length > 0 ? (
|
||||
<TabsState currentTabId={folderId} orientation="vertical" localState={innerTabState} lazy onChange={openFolder}>
|
||||
<SContext registry={objectFoldersRegistry}>
|
||||
<TabList aria-label="Object folders" vertical>
|
||||
{folders.map(folderId => (
|
||||
<FolderTabRenderer key={folderId} nodeId={nodeId} folderId={folderId} parents={parents} />
|
||||
))}
|
||||
</TabList>
|
||||
<div>
|
||||
<TabList aria-label="Object folders" vertical>
|
||||
{folders.map(folderId => (
|
||||
<FolderTabRenderer key={folderId} nodeId={nodeId} folderId={folderId} parents={parents} />
|
||||
))}
|
||||
</TabList>
|
||||
</div>
|
||||
{folders.map(folderId => (
|
||||
<TabPanel key={folderId} tabId={folderId}>
|
||||
<TabPanel key={folderId} className="theme-background-surface" tabId={folderId}>
|
||||
<FolderPanelRenderer key={folderId} nodeId={nodeId} folderId={folderId} parents={parents} />
|
||||
</TabPanel>
|
||||
))}
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -8,6 +8,7 @@
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
import { s, useS } from '@cloudbeaver/core-blocks';
|
||||
import { useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
|
||||
import type { ObjectPagePanelComponent } from '../ObjectPage/ObjectPage.js';
|
||||
import { ObjectFolders } from './ObjectFolders.js';
|
||||
@@ -15,9 +16,10 @@ import classes from './ObjectPropertiesPagePanel.module.css';
|
||||
|
||||
export const ObjectPropertiesPagePanel: ObjectPagePanelComponent = observer(function ObjectPropertiesPagePanel({ tab }) {
|
||||
const styles = useS(classes);
|
||||
const typeColor = useConnectionTypeColor(tab.handlerState.connectionKey);
|
||||
|
||||
return (
|
||||
<div className={s(styles, { wrapper: true })}>
|
||||
<div className={s(styles, { wrapper: true })} style={{ background: typeColor }}>
|
||||
<ObjectFolders tab={tab} />
|
||||
</div>
|
||||
);
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2025 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -50,7 +50,7 @@ export const ObjectPropertyTable = observer<ObjectPropertyTableProps>(function O
|
||||
<TextPlaceholder>{translate('plugin_object_viewer_table_no_items')}</TextPlaceholder>
|
||||
) : (
|
||||
<div className={s(styles, { box: true }, className)}>
|
||||
<TableLoader objects={objects} hasNextPage={pagination.hasNextPage} loadMore={pagination.loadMore} />
|
||||
<TableLoader objects={objects} hasNextPage={pagination.hasNextPage} objectId={objectId} loadMore={pagination.loadMore} />
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
+3
-2
@@ -20,9 +20,10 @@ import { MENU_OBJECT_VIEWER_FOOTER } from './MENU_OBJECT_VIEWER_FOOTER.js';
|
||||
interface Props {
|
||||
state: TableState;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export const ObjectPropertyTableFooter = observer<Props>(function ObjectPropertyTableFooter({ state, className }) {
|
||||
export const ObjectPropertyTableFooter = observer<Props>(function ObjectPropertyTableFooter({ state, className, style }) {
|
||||
const styles = useS(MenuBarStyles, MenuBarItemStyles, MenuBarGroupStyles);
|
||||
const navNodeInfoResource = useService(NavNodeInfoResource);
|
||||
const menu = useMenu({ menu: MENU_OBJECT_VIEWER_FOOTER });
|
||||
@@ -35,5 +36,5 @@ export const ObjectPropertyTableFooter = observer<Props>(function ObjectProperty
|
||||
context.set(DATA_CONTEXT_NAV_NODES, getSelected, id);
|
||||
});
|
||||
|
||||
return <MenuBar className={s(styles, { floating: true, withLabel: true }, className)} menu={menu} compact={false} />;
|
||||
return <MenuBar className={s(styles, { floating: true, withLabel: true }, className)} style={style} menu={menu} compact={false} />;
|
||||
});
|
||||
|
||||
+10
-3
@@ -16,19 +16,22 @@ import { useTabLocalState } from '@cloudbeaver/core-ui';
|
||||
import { DataGrid, useCreateGridReactiveValue } from '@cloudbeaver/plugin-data-grid';
|
||||
import { getObjectPropertyDisplayValue, getObjectPropertyType, getObjectPropertyValue } from '@cloudbeaver/core-sdk';
|
||||
import { CheckboxIndicator } from '@dbeaver/ui-kit';
|
||||
import { useNode } from '@cloudbeaver/plugin-navigation-tree';
|
||||
|
||||
import { ObjectPropertyTableFooter } from '../ObjectPropertyTableFooter.js';
|
||||
import classes from './Table.module.css';
|
||||
import { ObjectMenuCell } from './ObjectMenuCell.js';
|
||||
import { SelectorFormatter } from './Columns/ColumnSelect/SelectorFormatter.js';
|
||||
import { createConnectionParam, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
|
||||
export interface TableProps {
|
||||
export interface ITableProps {
|
||||
objects: DBObject[];
|
||||
hasNextPage: boolean;
|
||||
objectId: string;
|
||||
loadMore: () => void;
|
||||
}
|
||||
|
||||
export const Table = observer<TableProps>(function Table({ objects, hasNextPage, loadMore }) {
|
||||
export const Table = observer<ITableProps>(function Table({ objects, hasNextPage, objectId, loadMore }) {
|
||||
const styles = useS(classes);
|
||||
const navTreeResource = useService(NavTreeResource);
|
||||
|
||||
@@ -37,6 +40,7 @@ export const Table = observer<TableProps>(function Table({ objects, hasNextPage,
|
||||
|
||||
const tableState = useTable();
|
||||
const tabLocalState = useTabLocalState<IScrollState>(() => ({ scrollTop: 0, scrollLeft: 0 }));
|
||||
const { node } = useNode(objectId);
|
||||
|
||||
const scrollBox = tableContainer?.querySelector<HTMLDivElement>('[role="grid"]') ?? null;
|
||||
useControlledScroll(scrollBox, tabLocalState);
|
||||
@@ -135,6 +139,9 @@ export const Table = observer<TableProps>(function Table({ objects, hasNextPage,
|
||||
return colIdx !== 0;
|
||||
}
|
||||
|
||||
const connectionKey = node?.objectId && node.projectId ? createConnectionParam(node.projectId, node.objectId) : undefined;
|
||||
const typeColor = useConnectionTypeColor(connectionKey);
|
||||
|
||||
if (objects.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -160,7 +167,7 @@ export const Table = observer<TableProps>(function Table({ objects, hasNextPage,
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
<ObjectPropertyTableFooter className={s(styles, { objectPropertyTableFooter: true })} state={tableState} />
|
||||
<ObjectPropertyTableFooter className={s(styles, { objectPropertyTableFooter: true })} state={tableState} style={{ background: typeColor }} />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -9,12 +9,12 @@ import { observer } from 'mobx-react-lite';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { useObjectInfoTooltip } from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionInfoResource } from '@cloudbeaver/core-connections';
|
||||
import { ConnectionInfoResource, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
import { useDataContext } from '@cloudbeaver/core-data-context';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NavNodeManagerService } from '@cloudbeaver/core-navigation-tree';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { type ITabData, Tab, TabIcon, TabTitle } from '@cloudbeaver/core-ui';
|
||||
import { type ITabData, Tab, TabIcon, TabTitle, useTab } from '@cloudbeaver/core-ui';
|
||||
import { CaptureViewContext } from '@cloudbeaver/core-view';
|
||||
import type { TabHandlerTabComponent } from '@cloudbeaver/plugin-navigation-tabs';
|
||||
import { useNode } from '@cloudbeaver/plugin-navigation-tree';
|
||||
@@ -36,9 +36,18 @@ export const ObjectViewerTab: TabHandlerTabComponent<IObjectViewerTabState> = ob
|
||||
const nodeInfo = node ? navNodeManagerService.getNodeContainerInfo(node.uri) : undefined;
|
||||
|
||||
const tooltip = useObjectInfoTooltip(connection?.name, nodeInfo?.catalogId, nodeInfo?.schemaId, project?.name);
|
||||
const { selected } = useTab(tab.id);
|
||||
const typeColor = useConnectionTypeColor(tab.handlerState.connectionKey);
|
||||
|
||||
return (
|
||||
<Tab tabId={tab.id} title={`${title}${tooltip ? '\n' + tooltip : ''}`} menuContext={tabMenuContext} onOpen={handleSelect} onClose={handleClose}>
|
||||
<Tab
|
||||
style={{ backgroundColor: selected ? undefined : typeColor }}
|
||||
tabId={tab.id}
|
||||
title={`${title}${tooltip ? '\n' + tooltip : ''}`}
|
||||
menuContext={tabMenuContext}
|
||||
onOpen={handleSelect}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<TabIcon icon={node?.icon || tab.handlerState.tabIcon} />
|
||||
<TabTitle>{title}</TabTitle>
|
||||
</Tab>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* CloudBeaver - Cloud Database Manager
|
||||
* Copyright (C) 2020-2024 DBeaver Corp and others
|
||||
* Copyright (C) 2020-2026 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0.
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -9,11 +9,11 @@ import { observer } from 'mobx-react-lite';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { IconOrImage, s, useObjectInfoTooltip, useTranslate } from '@cloudbeaver/core-blocks';
|
||||
import { ConnectionInfoResource, createConnectionParam } from '@cloudbeaver/core-connections';
|
||||
import { ConnectionInfoResource, createConnectionParam, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
import { useDataContext, useDataContextLink } from '@cloudbeaver/core-data-context';
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
|
||||
import { type ITabData, Tab, TabIcon, TabTitle } from '@cloudbeaver/core-ui';
|
||||
import { type ITabData, Tab, TabIcon, TabTitle, useTab } from '@cloudbeaver/core-ui';
|
||||
import { CaptureViewContext } from '@cloudbeaver/core-view';
|
||||
import type { TabHandlerTabComponent } from '@cloudbeaver/plugin-navigation-tabs';
|
||||
import {
|
||||
@@ -32,6 +32,8 @@ export const SqlEditorTab: TabHandlerTabComponent<ISqlEditorTabState> = observer
|
||||
const tabMenuContext = useDataContext(viewContext);
|
||||
const handlerState = tab.handlerState;
|
||||
|
||||
const { selected } = useTab(tab.id);
|
||||
|
||||
useDataContextLink(tabMenuContext, (context, id) => {
|
||||
context.set(DATA_CONTEXT_SQL_EDITOR_TAB, true, id);
|
||||
context.set(DATA_CONTEXT_SQL_EDITOR_STATE, handlerState, id);
|
||||
@@ -61,9 +63,18 @@ export const SqlEditorTab: TabHandlerTabComponent<ISqlEditorTabState> = observer
|
||||
const handleClose = onClose ? ({ tabId }: ITabData<any>) => onClose(tabId) : undefined;
|
||||
|
||||
const tooltip = useObjectInfoTooltip(connection?.name, executionContext?.defaultCatalog, executionContext?.defaultSchema, project?.name);
|
||||
const connectionKey = executionContext ? createConnectionParam(executionContext.projectId, executionContext.connectionId) : undefined;
|
||||
const typeColor = useConnectionTypeColor(connectionKey);
|
||||
|
||||
return (
|
||||
<Tab tabId={tab.id} title={`${name}${tooltip ? '\n' + tooltip : ''}`} menuContext={tabMenuContext} onOpen={handleSelect} onClose={handleClose}>
|
||||
<Tab
|
||||
style={{ backgroundColor: selected ? undefined : typeColor }}
|
||||
tabId={tab.id}
|
||||
title={`${name}${tooltip ? '\n' + tooltip : ''}`}
|
||||
menuContext={tabMenuContext}
|
||||
onOpen={handleSelect}
|
||||
onClose={handleClose}
|
||||
>
|
||||
<TabIcon icon={icon} />
|
||||
<TabTitle>{name}</TabTitle>
|
||||
{isReadonly && isScript && (
|
||||
|
||||
@@ -15,7 +15,7 @@ import type { ISqlEditorTabState } from '../ISqlEditorTabState.js';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_DATA } from './DATA_CONTEXT_SQL_EDITOR_DATA.js';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_STATE } from '../DATA_CONTEXT_SQL_EDITOR_STATE.js';
|
||||
import type { ISQLEditorData } from './ISQLEditorData.js';
|
||||
import style from './SQLEditorActions.module.css';
|
||||
import componentStyle from './SQLEditorActions.module.css';
|
||||
import { SqlEditorActionsMenu } from './SqlEditorActionsMenu.js';
|
||||
import { SqlEditorTools } from './SqlEditorTools.js';
|
||||
import { SQL_EDITOR_ACTIONS_MENU } from './SQL_EDITOR_ACTIONS_MENU.js';
|
||||
@@ -24,10 +24,11 @@ interface Props {
|
||||
data: ISQLEditorData;
|
||||
state: ISqlEditorTabState;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export const SQLEditorActions = observer<Props>(function SQLEditorActions({ data, state, className }) {
|
||||
const styles = useS(style);
|
||||
export const SQLEditorActions = observer<Props>(function SQLEditorActions({ data, state, className, style }) {
|
||||
const styles = useS(componentStyle);
|
||||
const menu = useMenu({ menu: SQL_EDITOR_ACTIONS_MENU });
|
||||
|
||||
useDataContextLink(menu.context, (context, id) => {
|
||||
@@ -38,7 +39,7 @@ export const SQLEditorActions = observer<Props>(function SQLEditorActions({ data
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={s(styles, { container: true }, className)}>
|
||||
<div className={s(styles, { container: true }, className)} style={style}>
|
||||
<div className={s(styles, { actions: true })} onMouseDown={preventFocusHandler}>
|
||||
<SqlEditorActionsMenu state={state} context={menu.context} />
|
||||
</div>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useService } from '@cloudbeaver/core-di';
|
||||
import { type ITabData, TabList, TabListStyles, TabPanelList, TabsState, TabStyles } from '@cloudbeaver/core-ui';
|
||||
import { MetadataMap } from '@cloudbeaver/core-utils';
|
||||
import { useCaptureViewContext } from '@cloudbeaver/core-view';
|
||||
import { createConnectionParam, useConnectionTypeColor } from '@cloudbeaver/core-connections';
|
||||
|
||||
import { type ISqlEditorModeProps, SqlEditorModeService } from '../SqlEditorModeService.js';
|
||||
import { DATA_CONTEXT_SQL_EDITOR_DATA } from './DATA_CONTEXT_SQL_EDITOR_DATA.js';
|
||||
@@ -33,6 +34,7 @@ export const SqlEditor = observer<ISqlEditorProps>(function SqlEditor({ state, c
|
||||
const split = useSplit();
|
||||
const style = useS(styles, SqlEditorTab);
|
||||
const sqlEditorModeService = useService(SqlEditorModeService);
|
||||
|
||||
const data = useSqlEditor(state);
|
||||
useActiveQuery(data);
|
||||
const [modesState] = useState(() => new MetadataMap<string, any>());
|
||||
@@ -60,6 +62,10 @@ export const SqlEditor = observer<ISqlEditorProps>(function SqlEditor({ state, c
|
||||
}
|
||||
}, [isEditorEmpty]);
|
||||
|
||||
const context = data.model.dataSource?.executionContext;
|
||||
const connectionKey = context ? createConnectionParam(context.projectId, context.connectionId) : undefined;
|
||||
const typeColor = useConnectionTypeColor(connectionKey);
|
||||
|
||||
return (
|
||||
<TabsState
|
||||
currentTabId={state.currentModeId}
|
||||
@@ -72,10 +78,10 @@ export const SqlEditor = observer<ISqlEditorProps>(function SqlEditor({ state, c
|
||||
>
|
||||
<SContext registry={sqlEditorRegistry}>
|
||||
<div className={s(style, { sqlEditor: true }, className)}>
|
||||
<SQLEditorActions data={data} state={state} />
|
||||
<SQLEditorActions data={data} state={state} style={{ background: typeColor }} />
|
||||
<TabPanelList />
|
||||
{displayedEditors > 1 ? (
|
||||
<div className={s(style, { tabs: true })}>
|
||||
<div className={s(style, { tabs: true })} style={{ background: typeColor }}>
|
||||
<TabList vertical rotated />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -1688,6 +1688,7 @@ __metadata:
|
||||
"@cloudbeaver/core-root": "workspace:*"
|
||||
"@cloudbeaver/core-sdk": "workspace:*"
|
||||
"@cloudbeaver/core-settings": "workspace:*"
|
||||
"@cloudbeaver/core-theming": "workspace:*"
|
||||
"@cloudbeaver/core-utils": "workspace:*"
|
||||
"@cloudbeaver/tests-runner": "workspace:*"
|
||||
"@cloudbeaver/tsconfig": "workspace:*"
|
||||
@@ -2896,6 +2897,7 @@ __metadata:
|
||||
"@cloudbeaver/tsconfig": "workspace:*"
|
||||
"@dbeaver/jdbc-uri-parser": "workspace:*"
|
||||
"@dbeaver/js-helpers": "workspace:*"
|
||||
"@dbeaver/ui-kit": "workspace:*"
|
||||
"@types/react": "npm:^19"
|
||||
mobx: "npm:^6"
|
||||
mobx-react-lite: "npm:^4"
|
||||
@@ -3576,6 +3578,7 @@ __metadata:
|
||||
"@cloudbeaver/core-authentication": "workspace:*"
|
||||
"@cloudbeaver/core-blocks": "workspace:*"
|
||||
"@cloudbeaver/core-cli": "workspace:*"
|
||||
"@cloudbeaver/core-connections": "workspace:*"
|
||||
"@cloudbeaver/core-di": "workspace:*"
|
||||
"@cloudbeaver/core-events": "workspace:*"
|
||||
"@cloudbeaver/core-executor": "workspace:*"
|
||||
|
||||
Reference in New Issue
Block a user