CB-3100 rm event for creating project (#1453)

* CB-3100 rm event for creating project

* CB-3100 fix: display projects in multiproject mode

---------

Co-authored-by: Wroud <wroud@yandex.ru>
Co-authored-by: MarinaVorobeva21 <98399603+MarinaVorobeva21@users.noreply.github.com>
Co-authored-by: Aleksey Potsetsuev <wrouds@gmail.com>
This commit is contained in:
Ainur
2023-02-15 11:09:59 +03:00
committed by GitHub
co-authored by Wroud MarinaVorobeva21 Aleksey Potsetsuev
parent 662bad583e
commit 3f687ac419
17 changed files with 118 additions and 76 deletions
@@ -28,6 +28,7 @@ import org.jkiss.dbeaver.model.navigator.DBNNode;
import org.jkiss.dbeaver.model.navigator.DBNRoot;
import org.jkiss.dbeaver.model.rm.*;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.utils.ArrayUtils;
import java.util.*;
@@ -127,6 +128,9 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
case RESOURCE_ADD:
addResourceNode(event.getProject(), event.getResourceTree());
break;
case PROJECT_ADD:
addProjectNode(event.getProject());
break;
}
}
@@ -146,4 +150,8 @@ public class DBNResourceManagerRoot extends DBNNode implements DBPHiddenObject,
var projectNode = getProjectNode(project);
projectNode.ifPresent(dbnResourceManagerProject -> dbnResourceManagerProject.addChildResourceNode(new ArrayDeque<>(resourcePath)));
}
private void addProjectNode(RMProject project) {
projects = ArrayUtils.add(DBNResourceManagerProject.class, projects, new DBNResourceManagerProject(this, project));
}
}
@@ -268,6 +268,7 @@ public class LocalResourceController implements RMController {
}
try {
Files.createDirectories(getProjectPath(project.getId()));
fireRmProjectAddEvent(project);
return project;
} catch (IOException e) {
throw new DBException("Error creating project path", e);
@@ -900,6 +901,14 @@ public class LocalResourceController implements RMController {
);
}
private void fireRmProjectAddEvent(@NotNull RMProject project) throws DBException {
RMEventManager.fireEvent(
new RMEvent(RMEvent.Action.RESOURCE_ADD,
project
)
);
}
public static Builder builder(SMCredentialsProvider credentialsProvider, Supplier<SMController> smControllerSupplier) {
return new Builder(credentialsProvider, smControllerSupplier);
}
@@ -30,7 +30,8 @@ interface IDNDDataPrivate extends IDNDData {
}
interface IOptions {
onDragStart: () => void;
onDragStart?: () => void;
onDragEnd?: () => void;
}
export function useDNDData(context: IDataContextProvider, options: IOptions): IDNDData {
@@ -47,8 +48,12 @@ export function useDNDData(context: IDataContextProvider, options: IOptions): ID
collect: monitor => {
const dragging = monitor.isDragging();
if (dragging !== state.isDragging && dragging) {
options.onDragStart();
if (dragging !== state.isDragging) {
if (dragging) {
options.onDragStart?.();
} else {
options.onDragEnd?.();
}
}
state.isDragging = monitor.isDragging();
@@ -46,7 +46,7 @@ function sortManageable(): (nodeA: NavNode, nodeB: NavNode) => number {
export function navigationTreeConnectionGroupFilter(
resource: NavNodeInfoResource
): IElementsTreeFilter {
return (filter: string, node: NavNode, children: string[]) => {
return (tree, filter, node, children) => {
if (node.id !== ROOT_NODE_PATH) {
return children;
}
@@ -6,7 +6,7 @@
* you may not use this file except in compliance with the License.
*/
import type { NavNode, NavTreeResource } from '@cloudbeaver/core-navigation-tree';
import type { NavTreeResource } from '@cloudbeaver/core-navigation-tree';
import type { IElementsTreeFilter } from '../useElementsTree';
@@ -18,11 +18,7 @@ export function elementsTreeLimitFilter(
navTreeResource: NavTreeResource,
limit?: number
): IElementsTreeFilter {
return (
filter: string,
node: NavNode,
children: string[],
) => {
return (tree, filter, node, children) => {
limit = limit ?? navTreeResource.childrenLimit;
const nextChildren = children.slice(0, limit);
@@ -7,6 +7,7 @@
*/
import { observer } from 'mobx-react-lite';
import { useEffect } from 'react';
import styled, { use, css } from 'reshadow';
import { getComputed, TreeNode, useStyles } from '@cloudbeaver/core-blocks';
@@ -37,75 +38,67 @@ export const NavigationNode: NavigationNodeComponent = observer(function Navigat
style,
}) {
const navNodeManagerService = useService(NavNodeManagerService);
const {
ref,
group,
control,
disabled,
selected,
indeterminateSelected,
loading,
loaded,
showInFilter,
expanded,
leaf,
click,
expand,
open,
select,
getSelected,
} = useNavigationNode(node, path);
const navNode = useNavigationNode(node, path);
const context = useDataContext();
const dndData = useDNDData(context, {
onDragStart: async () => {
if (!selected) {
select(false);
if (!navNode.selected) {
navNode.select(false);
}
navNode.setDnDState(dndData, true);
// strange way to preload alias while dragging
await navNodeManagerService.getNodeDatabaseAlias(node.id);
},
});
const dndBox = useNavTreeDropBox(node, {
expanded,
expand,
onDragEnd: () => {
navNode.setDnDState(dndData, false);
},
});
const dndBox = useNavTreeDropBox(node, {
expanded: navNode.expanded,
expand: navNode.expand,
});
context.set(DATA_CONTEXT_NAV_NODE, node);
context.set(DATA_CONTEXT_NAV_NODES, getSelected);
context.set(DATA_CONTEXT_NAV_NODES, navNode.getSelected);
const Control = control || externalControl || NavigationNodeControl;
const Control = navNode.control || externalControl || NavigationNodeControl;
if (leaf || !loaded) {
if (navNode.leaf || !navNode.loaded) {
externalExpanded = false;
}
function setRef(refObj: HTMLDivElement | null) {
//@ts-expect-error ignore
ref.current = refObj;
navNode.ref.current = refObj;
dndData.setTargetRef(refObj);
}
const hasNodes = getComputed(() => !!dndBox.state.context && dndBox.state.canDrop && dndBox.state.isOverCurrent);
useEffect(() => () => {
navNode.setDnDState(dndData, false);
}, []);
return styled(useStyles(style, styles))(
<TreeNode
ref={dndBox.setRef}
group={group}
loading={loading}
disabled={disabled}
selected={selected}
indeterminateSelected={indeterminateSelected}
expanded={expanded}
showInFilter={showInFilter}
group={navNode.group}
loading={navNode.loading}
disabled={navNode.disabled}
selected={navNode.selected}
indeterminateSelected={navNode.indeterminateSelected}
expanded={navNode.expanded}
showInFilter={navNode.showInFilter}
externalExpanded={externalExpanded}
leaf={leaf}
leaf={navNode.leaf}
className={className}
onExpand={expand}
onClick={click}
onOpen={open}
onSelect={select}
onExpand={navNode.expand}
onClick={navNode.click}
onOpen={navNode.open}
onSelect={navNode.select}
{...use({ hovered: hasNodes })}
>
{/* <DNDPreview data={dndData} src="/icons/empty.svg" /> */}
@@ -115,7 +108,7 @@ export const NavigationNode: NavigationNodeComponent = observer(function Navigat
style={style}
node={node}
/>
{(expanded || externalExpanded) && (
{(navNode.expanded || externalExpanded) && (
<NavigationNodeNested
nodeId={node.id}
path={path}
@@ -13,6 +13,7 @@ import { useService } from '@cloudbeaver/core-di';
import { SyncExecutor } from '@cloudbeaver/core-executor';
import { type NavNode, NavNodeInfoResource, EObjectFeature } from '@cloudbeaver/core-navigation-tree';
import { resourceKeyList } from '@cloudbeaver/core-sdk';
import type { IDNDData } from '@cloudbeaver/core-ui';
import { useChildren } from '../../../NodesManager/useChildren';
import { useNode } from '../../../NodesManager/useNode';
@@ -41,6 +42,7 @@ interface INavigationNode {
click: (leaf: boolean) => Promise<void>;
select: (isMultiple?: boolean, nested?: boolean) => Promise<void>;
getSelected: () => NavNode[];
setDnDState: (data: IDNDData, dragging: boolean) => void;
}
export function useNavigationNode(node: NavNode, path: string[]): INavigationNode {
@@ -79,6 +81,10 @@ export function useNavigationNode(node: NavNode, path: string[]): INavigationNod
nested = false
) => await contextRef.context?.tree.select(node, multiple, nested);
function setDnDState(data: IDNDData, dragging: boolean): void {
contextRef.context?.tree.setDnDData(data, dragging);
}
useEffect(() => () => {
if (!contextRef.context?.selectionTree) {
if (contextRef.context?.tree.isNodeSelected(node.id)) {
@@ -102,7 +108,7 @@ export function useNavigationNode(node: NavNode, path: string[]): INavigationNod
}],
});
return {
return useObjectRef({
ref: elementRef,
showInFilter,
empty,
@@ -121,7 +127,8 @@ export function useNavigationNode(node: NavNode, path: string[]): INavigationNod
open: handleOpen,
select: handleSelect,
getSelected,
};
setDnDState,
});
}
export function isLeaf(node: NavNode, children: string[] | undefined, tree: IElementsTree | undefined): boolean {
@@ -22,7 +22,7 @@ export function elementsTreeNameFilter(
navNodeInfoResource: NavNodeInfoResource,
compare: NavNodeFilterCompareFn = elementsTreeNameFilterNode
): IElementsTreeFilter {
return (filter: string, node: NavNode, children: string[], state: MetadataMap<string, ITreeNodeState>) => {
return (tree, filter, node, children, state) => {
const nodeState = state.get(node.id);
if (filter === '' || nodeState.showInFilter || compare(node, filter) === EEquality.full) {
@@ -17,6 +17,7 @@ import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
import { type NavNode, NavNodeInfoResource, NavTreeResource } from '@cloudbeaver/core-navigation-tree';
import { ProjectInfoResource, ProjectsService } from '@cloudbeaver/core-projects';
import { CachedMapAllKey, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
import type { IDNDData } from '@cloudbeaver/core-ui';
import { ILoadableState, MetadataMap, throttle } from '@cloudbeaver/core-utils';
import type { IElementsTreeAction } from './IElementsTreeAction';
@@ -30,11 +31,13 @@ export interface IElementsTreeNodeExpandedInfo {
}
export type IElementsTreeNodeExpandInfoGetter = (
tree: IElementsTree,
nodeId: string,
state: ITreeNodeState
) => IElementsTreeNodeExpandedInfo | null;
export type IElementsTreeFilter = (
tree: IElementsTree,
filter: string,
node: NavNode,
children: string[],
@@ -96,6 +99,7 @@ export interface IElementsTree extends ILoadableState {
readonly filter: string;
loading: boolean;
disabled: boolean;
activeDnDData: IDNDData[];
renderers: IElementsTreeCustomRenderer[];
state: MetadataMap<string, ITreeNodeState>;
userData: IElementsTreeUserState;
@@ -112,6 +116,7 @@ export interface IElementsTree extends ILoadableState {
setFilter: (value: string) => Promise<void>;
select: (node: NavNode, multiple: boolean, nested: boolean) => Promise<void>;
resetSelection(): Promise<void>;
setDnDData: (data: IDNDData, dragging: boolean) => void;
expand: (node: NavNode, state: boolean) => Promise<void>;
show: (nodeId: string, parents: string[]) => Promise<void>;
refresh: (nodeId: string) => Promise<void>;
@@ -303,6 +308,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
const elementsTree = useObservableRef<IElementsTree>(() => ({
actions: new SyncExecutor(),
state,
activeDnDData: [],
loading: options.settings?.saveExpanded || false,
get filter(): string {
return this.userData.filter;
@@ -334,7 +340,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
if (!expanded && options.expandStateGetters?.length) {
return options
.expandStateGetters
.map(getExpandState => getExpandState(nodeId, nodeState))
.map(getExpandState => getExpandState(this, nodeId, nodeState))
.filter(stateInfo => stateInfo !== null)
.some(stateInfo => stateInfo?.expanded);
}
@@ -351,7 +357,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
return options
.expandStateGetters
.map(getExpandState => getExpandState(nodeId, nodeState))
.map(getExpandState => getExpandState(this, nodeId, nodeState))
.filter(stateInfo => stateInfo !== null)
.every(stateInfo => stateInfo?.expandable !== false);
}
@@ -407,7 +413,7 @@ export function useElementsTree(options: IOptions): IElementsTree {
return (options.filters || [])
.reduce(
(children, filter) => filter(elementsTree.filter, node, children, this.state),
(children, filter) => filter(elementsTree, elementsTree.filter, node, children, this.state),
options.getChildren(node.id) || []
);
},
@@ -531,10 +537,20 @@ export function useElementsTree(options: IOptions): IElementsTree {
}
await functionsRef.resetSelection();
},
setDnDData(data: IDNDData, dragging: boolean) {
if (dragging) {
if (!this.activeDnDData.includes(data)) {
this.activeDnDData.push(data);
}
} else {
this.activeDnDData = this.activeDnDData.filter(d => d !== data);
}
},
}), {
settings: observable.ref,
isGroup: observable.ref,
disabled: observable.ref,
activeDnDData: observable.shallow,
root: observable.ref,
filter: computed,
filtering: computed,
@@ -19,7 +19,7 @@ export function navigationTreeProjectFilter(
navNodeInfoResource: NavNodeInfoResource,
navTreeResource: NavTreeResource,
): IElementsTreeFilter {
return (filter: string, node: NavNode, children: string[]) => {
return (tree, filter, node, children) => {
if (node.id !== ROOT_NODE_PATH) {
return children;
}
@@ -18,7 +18,7 @@ export function navigationTreeProjectsExpandStateGetter(
projectsNavNodeService: ProjectsNavNodeService
): IElementsTreeNodeExpandInfoGetter {
return nodeId => {
return (tree, nodeId) => {
const node = navNodeInfoResource.get(nodeId);
if (node?.nodeType !== NAV_NODE_TYPE_PROJECT) {
@@ -8,15 +8,13 @@
import { untracked } from 'mobx';
import type { NavNode } from '@cloudbeaver/core-navigation-tree';
import type { NavNodeViewService } from '../NodesManager/NavNodeView/NavNodeViewService';
import type { IElementsTreeFilter } from './ElementsTree/useElementsTree';
export function navigationTreeDuplicateFilter(
navNodeViewService: NavNodeViewService,
): IElementsTreeFilter {
return (filter: string, node: NavNode, children: string[]) => {
return (tree, filter, node, children) => {
const { nodes, duplicates } = navNodeViewService.filterDuplicates(children);
untracked(() => {
@@ -14,11 +14,13 @@ import { getComputed, TreeNodeContext, TreeNodeControl, TreeNodeName, TREE_NODE_
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, NavigationNodeEditor, NavTreeControlComponent, NavTreeControlProps, TreeNodeMenu } 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';
@@ -65,7 +67,9 @@ export const NavigationNodeProjectControl: NavTreeControlComponent = observer<Na
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);
@@ -88,17 +92,23 @@ export const NavigationNodeProjectControl: NavTreeControlComponent = observer<Na
treeNodeContext.select(event.ctrlKey || event.metaKey);
}
if (
node.nodeType === NAV_NODE_TYPE_RM_PROJECT
&& resourceType !== undefined
) {
return null;
} else if (resourceType !== undefined && node.projectId) {
const project = getRmProjectNodeId(node.projectId);
const projectName = navNodeInfoResource.get(project)?.name;
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 (projectName) {
name = projectName;
if (resourceFolder !== undefined) {
return null;
}
}
} else {
const project = getRmProjectNodeId(node.projectId);
const projectName = navNodeInfoResource.get(project)?.name;
if (projectName) {
name = projectName;
}
}
}
@@ -24,7 +24,7 @@ export function navigationTreeProjectFilter(
resourceManagerService: ResourceManagerService,
resourceTypeId?: string,
): IElementsTreeFilter {
return (filter: string, node: NavNode, children: string[]) => {
return (tree, filter, node, children) => {
if (node.nodeType === NAV_NODE_TYPE_RM_PROJECT && resourceTypeId !== undefined) {
const project = projectsNavNodeService.getProject(node.id);
@@ -18,7 +18,7 @@ export function navigationTreeProjectsExpandStateGetter(
projectsNavNodeService: ProjectsNavNodeService,
): IElementsTreeNodeExpandInfoGetter {
return nodeId => {
return (tree, nodeId) => {
const node = navNodeInfoResource.get(nodeId);
if (node?.nodeType !== NAV_NODE_TYPE_RM_PROJECT) {
@@ -19,7 +19,7 @@ export function navigationTreeResourceTypeFilter(
projectInfoResource: ProjectInfoResource,
resourceTypeId?: string,
): IElementsTreeFilter {
return (filter: string, node: NavNode, children: string[]) => {
return (tree, filter, node, children) => {
if (resourceTypeId === undefined) {
return children;
}
@@ -20,7 +20,7 @@ export function navigationTreeResourceExpandStateGetter(
resourceTypeId?: string,
): IElementsTreeNodeExpandInfoGetter {
return nodeId => {
return (tree, nodeId) => {
const node = navNodeInfoResource.get(nodeId);
if (!node?.folder || resourceTypeId === undefined) {