diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebDatabaseObjectInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebDatabaseObjectInfo.java index 11d386ba7f..b97c43810c 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebDatabaseObjectInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebDatabaseObjectInfo.java @@ -23,12 +23,15 @@ import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.*; import org.jkiss.dbeaver.model.meta.Property; +import org.jkiss.dbeaver.model.navigator.DBNDataSource; +import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor; import org.jkiss.dbeaver.model.struct.*; import org.jkiss.dbeaver.model.struct.rdb.DBSCatalog; import org.jkiss.dbeaver.model.struct.rdb.DBSSchema; import org.jkiss.dbeaver.model.struct.rdb.DBSTable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; @@ -174,11 +177,12 @@ private static void getObjectFeatures(DBSObject object, List features) { } if (object instanceof DBSSchema) features.add(OBJECT_FEATURE_SCHEMA); if (object instanceof DBSCatalog) features.add(OBJECT_FEATURE_CATALOG); - if (object instanceof DBSObjectContainer) { + if (object instanceof DBSObjectContainer objectContainer) { features.add(OBJECT_FEATURE_OBJECT_CONTAINER); try { - Class childType = ((DBSObjectContainer) object).getPrimaryChildType(null); - if (DBSTable.class.isAssignableFrom(childType)) { + Class childType = objectContainer.getPrimaryChildType(null); + Collection childrenCollection = objectContainer.getChildren(null); + if (DBSTable.class.isAssignableFrom(childType) && childrenCollection != null) { features.add(OBJECT_FEATURE_ENTITY_CONTAINER); } } catch (Exception e) { diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java index 3767d799ac..6f22110e9f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/WebNavigatorNodeInfo.java @@ -36,6 +36,9 @@ import org.jkiss.dbeaver.model.navigator.*; import org.jkiss.dbeaver.model.navigator.fs.DBNFileSystem; import org.jkiss.dbeaver.model.navigator.fs.DBNPathBase; +import org.jkiss.dbeaver.model.navigator.meta.DBXTreeFolder; +import org.jkiss.dbeaver.model.navigator.meta.DBXTreeItem; +import org.jkiss.dbeaver.model.navigator.meta.DBXTreeNode; import org.jkiss.dbeaver.model.rm.RMProject; import org.jkiss.dbeaver.model.rm.RMProjectPermission; import org.jkiss.dbeaver.model.struct.DBSEntity; @@ -62,6 +65,7 @@ public class WebNavigatorNodeInfo { public static final String NODE_FEATURE_CONTAINER = "container"; public static final String NODE_FEATURE_SHARED = "shared"; public static final String NODE_FEATURE_CAN_DELETE = "canDelete"; + public static final String NODE_FEATURE_CAN_FILTER = "canFilter"; public static final String NODE_FEATURE_CAN_RENAME = "canRename"; private final WebSession session; private final DBNNode node; @@ -184,14 +188,30 @@ public String[] getFeatures() { if (object instanceof DBSEntity || object instanceof DBSProcedure) { features.add(NODE_FEATURE_LEAF); } - } if (node instanceof DBNContainer) { features.add(NODE_FEATURE_CONTAINER); } boolean isShared = false; if (node instanceof DBNDatabaseNode) { - isShared = !((DBNDatabaseNode) node).getOwnerProject().getName().equals(session.getUserId()); + if (node instanceof DBNDataSource dataSource) { + if (dataSource.getDataSourceContainer().getDataSource() != null) { + boolean hasNonFolderNode = DBXTreeNode.hasNonFolderNode(dataSource.getMeta().getChildren(null)); + if (hasNonFolderNode) { + features.add(NODE_FEATURE_CAN_FILTER); + } + } + } else if (node instanceof DBNDatabaseItem item) { + if (item.getDataSourceContainer().getDataSource() != null) { + boolean hasNonFolderNode = DBXTreeNode.hasNonFolderNode(item.getMeta().getChildren(null)); + if (hasNonFolderNode) { + features.add(NODE_FEATURE_CAN_FILTER); + } + } + } else { + features.add(NODE_FEATURE_CAN_FILTER); + } + isShared = !node.getOwnerProject().getName().equals(session.getUserId()); } else if (node instanceof DBNLocalFolder) { DataSourceFolder folder = (DataSourceFolder) ((DBNLocalFolder) node).getFolder(); DBPProject project = folder.getDataSourceRegistry().getProject(); @@ -300,10 +320,10 @@ public String getObjectId() { @Property public DBSObjectFilter getFilter() throws DBWebException { - if (!(node instanceof DBNDatabaseFolder)) { + if (!(node instanceof DBNDatabaseNode)) { throw new DBWebException("Invalid navigator node type: " + node.getClass().getName()); } - DBSObjectFilter filter = ((DBNDatabaseFolder) node).getNodeFilter(((DBNDatabaseFolder) node).getItemsMeta(), true); + DBSObjectFilter filter = ((DBNDatabaseNode) node).getNodeFilter(((DBNDatabaseNode) node).getItemsMeta(), true); return filter == null || filter.isEmpty() || !filter.isEnabled() ? null : filter; } diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java index 62da42bc4c..82e08f1b8f 100644 --- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java +++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/navigator/impl/WebServiceNavigator.java @@ -220,9 +220,6 @@ public boolean setNavigatorNodeFilter( if (node == null) { throw new DBWebException("Navigator node '" + nodePath + "' not found"); } - if (!(node instanceof DBNDatabaseFolder)) { - throw new DBWebException("Invalid navigator node type: " + node.getClass().getName()); - } DBSObjectFilter filter = new DBSObjectFilter(); if (!CommonUtils.isEmpty(include)) { filter.setInclude(include); @@ -231,11 +228,11 @@ public boolean setNavigatorNodeFilter( filter.setExclude(exclude); } filter.setEnabled(true); - ((DBNDatabaseFolder) node).setNodeFilter( - ((DBNDatabaseFolder) node).getItemsMeta(), filter, true); + ((DBNDatabaseNode) node).setNodeFilter( + ((DBNDatabaseNode) node).getItemsMeta(), filter, true); if (hasNodeEditPermission(webSession, node, ((WebProjectImpl) node.getOwnerProject()).getRmProject())) { // Save settings - ((DBNDatabaseFolder) node).getDataSourceContainer().persistConfiguration(); + ((DBNDatabaseNode) node).getDataSourceContainer().persistConfiguration(); } } catch (DBException e) { if (e instanceof DBWebException) { diff --git a/webapp/packages/core-navigation-tree/src/NodesManager/ENodeFeature.ts b/webapp/packages/core-navigation-tree/src/NodesManager/ENodeFeature.ts index 76ca926045..5d12871a5e 100644 --- a/webapp/packages/core-navigation-tree/src/NodesManager/ENodeFeature.ts +++ b/webapp/packages/core-navigation-tree/src/NodesManager/ENodeFeature.ts @@ -17,5 +17,6 @@ export enum ENodeFeature { 'leaf' = 'leaf', 'canDelete' = 'canDelete', 'canRename' = 'canRename', + 'canFilter' = 'canFilter', 'shared' = 'shared', } diff --git a/webapp/packages/plugin-navigation-tree-filters/src/NavigationTreeFiltersBootstrap.ts b/webapp/packages/plugin-navigation-tree-filters/src/NavigationTreeFiltersBootstrap.ts index 9f2ec81e9e..d69ec08a6b 100644 --- a/webapp/packages/plugin-navigation-tree-filters/src/NavigationTreeFiltersBootstrap.ts +++ b/webapp/packages/plugin-navigation-tree-filters/src/NavigationTreeFiltersBootstrap.ts @@ -10,7 +10,7 @@ import { Bootstrap, injectable } from '@cloudbeaver/core-di'; import { CommonDialogService } from '@cloudbeaver/core-dialogs'; import { NotificationService } from '@cloudbeaver/core-events'; import { LocalizationService } from '@cloudbeaver/core-localization'; -import { DATA_CONTEXT_NAV_NODE, NavTreeResource, NodeManagerUtils } from '@cloudbeaver/core-navigation-tree'; +import { DATA_CONTEXT_NAV_NODE, ENodeFeature, NavTreeResource, NodeManagerUtils } from '@cloudbeaver/core-navigation-tree'; import { DATA_CONTEXT_MENU, MenuBaseItem, MenuService } from '@cloudbeaver/core-view'; import { MENU_NAVIGATION_TREE_FILTERS } from './MENU_NAVIGATION_TREE_FILTERS'; @@ -38,7 +38,7 @@ export class NavigationTreeFiltersBootstrap extends Bootstrap { isApplicable: context => { const node = context.get(DATA_CONTEXT_NAV_NODE)!; - if (!node.folder || !NodeManagerUtils.isDatabaseObject(node.id)) { + if (!node.features?.includes(ENodeFeature.canFilter)) { return false; }