Files
cloudbeaver/webapp/packages/plugin-resource-manager/src/Tree/ProjectsRenderer/NavigationNodeProjectControl.tsx
T
Alexeyanddariamarutkina 64040bc3a3 CB-3372 feat: codemirror6 autocomplete (#1646)
* CB-3372 feat: codemirror6 autocomplete

* CB-3372 feat: autocomplete icons

* CB-3371 feat: sql editor syntax highlight

* CB-3371 fix: syntax highlight blinking

* CB-3371 fix: editor extensions state

* CB-3372 chore: code cleanup

* CB-3372 fix: remove useSqlDIalectAutocompletion

* CB-3372 fix: add useSqlDIalectAutocompletion

* CB-3372 feat: experimental context menu

* CB-3372 feat: use new sql editor

* CB-3372 chore: remove sql script parser

* CB-3372 fix: rounded menu

* CB-3372 fix: event preventDefault on dialog

* CB-3372 fix: context menu styles

* CB-3372 feat: remove old codemirror

* CB-3372 fix: numbers completion & extensions caching

* CB-3372 fix: table display

* CB-3372 fix: decrease sql editor font size

* CB-3372 fix: copy in readonly mode & autocompletion in safari on MacOS

* CB-3372 fix: value panel styles

* CB-3372 fix: menu bar styles

* CB-3372 fix: menu bar and inline editor styles

* CB-3372 fix: menu and inline editor styles

* CB-3372 chore: update bundle

---------

Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com>
2023-05-17 17:32:09 +03:00

163 lines
5.3 KiB
TypeScript

/*
* CloudBeaver - Cloud Database Manager
* Copyright (C) 2020-2023 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 React, { forwardRef, useContext, useState } from 'react';
import styled, { css, use } from 'reshadow';
import { getComputed, TreeNodeContext, TreeNodeControl, TreeNodeName, TREE_NODE_STYLES, useObjectRef, useMouseContextMenu } from '@cloudbeaver/core-blocks';
import { useService } from '@cloudbeaver/core-di';
import { EventContext, EventStopPropagationFlag } from '@cloudbeaver/core-events';
import { NavNodeInfoResource, type INodeActions } from '@cloudbeaver/core-navigation-tree';
import { ProjectInfoResource } from '@cloudbeaver/core-projects';
import { NAV_NODE_TYPE_RM_PROJECT } from '@cloudbeaver/core-resource-manager';
import { CaptureViewContext } from '@cloudbeaver/core-view';
import { ElementsTreeContext, isDraggingInsideProject, NavigationNodeEditorLoader, NavTreeControlComponent, NavTreeControlProps, TreeNodeMenuLoader } from '@cloudbeaver/plugin-navigation-tree';
import { getRmProjectNodeId } from '../../NavNodes/getRmProjectNodeId';
import { ResourceManagerService } from '../../ResourceManagerService';
import { DATA_CONTEXT_RESOURCE_MANAGER_TREE_RESOURCE_TYPE_ID } from '../DATA_CONTEXT_RESOURCE_MANAGER_TREE_RESOURCE_TYPE_ID';
const styles = css`
TreeNodeControl {
transition: opacity 0.3s ease;
opacity: 1;
&[|outdated] {
opacity: 0.5;
}
}
TreeNodeControl:hover > portal,
TreeNodeControl:global([aria-selected=true]) > portal,
portal:focus-within {
visibility: visible;
}
TreeNodeName {
composes: theme-text-text-hint-on-light theme-typography--caption from global;
height: 100%;
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
}
portal {
position: relative;
box-sizing: border-box;
margin-left: auto !important;
margin-right: 8px !important;
visibility: hidden;
}
name-box {
overflow: hidden;
text-overflow: ellipsis;
}
`;
export const NavigationNodeProjectControl: NavTreeControlComponent = observer<NavTreeControlProps, HTMLDivElement>(forwardRef(function NavigationNodeProjectControl({
node,
dndElement,
dndPlaceholder,
className,
}, ref) {
const mouseContextMenu = useMouseContextMenu();
const viewContext = useContext(CaptureViewContext);
const elementsTreeContext = useContext(ElementsTreeContext);
const treeNodeContext = useContext(TreeNodeContext);
const projectInfoResource = useService(ProjectInfoResource);
const navNodeInfoResource = useService(NavNodeInfoResource);
const resourceManagerService = useService(ResourceManagerService);
const outdated = getComputed(() => navNodeInfoResource.isOutdated(node.id) && !treeNodeContext.loading);
const selected = treeNodeContext.selected;
const resourceType = viewContext?.tryGet(DATA_CONTEXT_RESOURCE_MANAGER_TREE_RESOURCE_TYPE_ID);
const isDragging = getComputed(() => {
if (!node.projectId || !elementsTreeContext?.tree.activeDnDData) {
return false;
}
return isDraggingInsideProject(node.projectId, elementsTreeContext.tree.activeDnDData);
});
const [editing, setEditing] = useState(false);
let name = node.name;
const nodeActions = useObjectRef<INodeActions>({
rename: () => {
setEditing(true);
},
});
function handlePortalClick(event: React.MouseEvent<HTMLDivElement>) {
EventContext.set(event, EventStopPropagationFlag);
treeNodeContext.select();
}
function handleContextMenuOpen(event: React.MouseEvent<HTMLDivElement>) {
mouseContextMenu.handleContextMenuOpen(event);
treeNodeContext.select();
}
function handleClick(event: React.MouseEvent<HTMLDivElement>) {
treeNodeContext.select(event.ctrlKey || event.metaKey);
}
if (node.projectId && resourceType !== undefined) {
if (node.nodeType === NAV_NODE_TYPE_RM_PROJECT) {
const project = projectInfoResource.get(node.projectId);
if (project) {
const resourceFolder = resourceManagerService.getRootFolder(project, resourceType);
if (resourceFolder !== undefined) {
return null;
}
}
} else {
const project = getRmProjectNodeId(node.projectId);
const projectName = navNodeInfoResource.get(project)?.name;
if (projectName) {
name = projectName;
}
}
}
if (elementsTreeContext?.tree.settings?.projects === false && !isDragging) {
return null;
}
return styled(TREE_NODE_STYLES, styles)(
<TreeNodeControl
ref={ref}
onClick={handleClick}
onContextMenu={handleContextMenuOpen}
{...use({ outdated, editing, dragging: dndElement })}
className={className}
>
<TreeNodeName title={name}>
{editing ? (
<NavigationNodeEditorLoader node={node} onClose={() => setEditing(false)} />
) : (
<name-box>{name}</name-box>
)}
</TreeNodeName>
{!editing && !dndPlaceholder && (
<portal onClick={handlePortalClick}>
<TreeNodeMenuLoader
mouseContextMenu={mouseContextMenu}
node={node}
actions={nodeActions}
selected={selected}
/>
</portal>
)}
</TreeNodeControl>
);
}));