mirror of
https://github.com/dbeaver/cloudbeaver.git
synced 2026-09-24 16:04:36 +08:00
CB-2888 project sync (#1508)
* CB-3115 Add new create/delete project events Implements new events * CB-3115 Add new create/delete project events Renames WSProjectLifeCycleEvent to WSProjectLifeCycleEvent Adds BaseWebSession#addSessionEvent call in WsProjectLifeCycleEventHandler * CB-3127 events for project permissions * CB-2888 TE: Add synchronization for projects Renames WSProjectUpdatedEventHandler to WSAbstractProjectEventHandler and WsProjectLifeCycleEventHandler to WSProjectUpdatedEventHandler * CB-3127 code style fix * CB-3127 rename parameters * CB-3114 support project remove/add event * CB-3127 event filter fix * CB-2888 TE: Add synchronization for projects Moves validateEvent call to WSAbstractProjectEventHandler; Adds the use of an implementation class logger to the WSAbstractProjectEventHandler. * CB-2888 TE: Add synchronization for projects Fixes missed copyright * CB-3127 filter event fix * CB-2888 fix type naming * CB-3127 project update event add remove connections from session * CB-2888 TE: Add synchronization for projects Adds dispatch of project creation/deletion events to WebServiceRM * CB-3127 load connections when creating web project * CB-3114 update active projects on active project remove * CB-3114 update active projects via handler on project delete * CB-2888 mark root tree as outdated on project add event * CB-2888 move tree outdate logic to the useElementsTree hook * CB-2888 fix conflict with devel --------- Co-authored-by: Iaroslav Emelianov <iaroslav.emelianov@dbeaver.com> Co-authored-by: naumov <iamemptyhuh@gmail.com> Co-authored-by: dariamarutkina <125263541+dariamarutkina@users.noreply.github.com> Co-authored-by: Alexander Skoblikov <aleksandr.skoblikov@dbeaver.com>
This commit is contained in:
co-authored by
Iaroslav Emelianov
naumov
dariamarutkina
Alexander Skoblikov
parent
ba885fb7eb
commit
837d321b3f
+1
-1
@@ -190,7 +190,7 @@ public class LocalResourceController implements RMController {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private Set<RMProjectPermission> getProjectPermissions(@Nullable String projectId, RMProjectType projectType) throws DBException {
|
||||
private Set<RMProjectPermission> getProjectPermissions(@Nullable String projectId, @NotNull RMProjectType projectType) throws DBException {
|
||||
var activeUserCreds = credentialsProvider.getActiveUserCredentials();
|
||||
|
||||
switch (projectType) {
|
||||
|
||||
+9
@@ -19,6 +19,7 @@ package io.cloudbeaver.model.session;
|
||||
import io.cloudbeaver.model.app.WebApplication;
|
||||
import io.cloudbeaver.websocket.CBWebSessionEventHandler;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.auth.SMAuthInfo;
|
||||
@@ -168,4 +169,12 @@ public abstract class BaseWebSession extends AbstractSessionPersistent {
|
||||
public boolean isProjectAccessible(String projectId) {
|
||||
return userContext.getAccessibleProjectIds().contains(projectId);
|
||||
}
|
||||
|
||||
public void addSessionProject(@NotNull String projectId) throws DBException {
|
||||
userContext.getAccessibleProjectIds().add(projectId);
|
||||
}
|
||||
|
||||
public void removeSessionProject(@Nullable String projectId) throws DBException {
|
||||
userContext.getAccessibleProjectIds().remove(projectId);
|
||||
}
|
||||
}
|
||||
|
||||
+32
-35
@@ -302,6 +302,7 @@ public class WebSession extends BaseWebSession
|
||||
this.navigatorModel.dispose();
|
||||
this.navigatorModel = null;
|
||||
}
|
||||
this.connections.clear();
|
||||
|
||||
loadProjects();
|
||||
|
||||
@@ -310,13 +311,6 @@ public class WebSession extends BaseWebSession
|
||||
this.navigatorModel.initialize();
|
||||
|
||||
this.locale = Locale.getDefault().getLanguage();
|
||||
|
||||
try {
|
||||
this.refreshConnections();
|
||||
} catch (Exception e) {
|
||||
addSessionError(e);
|
||||
log.error("Error getting connection list", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadProjects() {
|
||||
@@ -360,35 +354,17 @@ public class WebSession extends BaseWebSession
|
||||
if (!project.isShared() || application.isConfigurationMode()) {
|
||||
getWorkspace().setActiveProject(sessionProject);
|
||||
}
|
||||
for (DBPDataSourceContainer ds : dataSourceRegistry.getDataSources()) {
|
||||
addConnection(new WebConnectionInfo(this, ds));
|
||||
}
|
||||
Throwable lastError = dataSourceRegistry.getLastError();
|
||||
if (lastError != null) {
|
||||
addSessionError(lastError);
|
||||
log.error("Error refreshing connections from project '" + project.getId() + "'", lastError);
|
||||
}
|
||||
return sessionProject;
|
||||
}
|
||||
|
||||
public void refreshConnections() {
|
||||
|
||||
// Add all provided datasources to the session
|
||||
List<WebConnectionInfo> connList = new ArrayList<>();
|
||||
for (DBPProject project : getWorkspace().getProjects()) {
|
||||
DBPDataSourceRegistry registry = project.getDataSourceRegistry();
|
||||
|
||||
for (DBPDataSourceContainer ds : registry.getDataSources()) {
|
||||
connList.add(new WebConnectionInfo(this, ds));
|
||||
}
|
||||
Throwable lastError = registry.getLastError();
|
||||
if (lastError != null) {
|
||||
addSessionError(lastError);
|
||||
log.error("Error refreshing connections from project '" + project.getId() + "'", lastError);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all provided datasources to the session
|
||||
synchronized (connections) {
|
||||
connections.clear();
|
||||
for (WebConnectionInfo connectionInfo : connList) {
|
||||
connections.put(connectionInfo.getId(), connectionInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void filterAccessibleConnections(List<WebConnectionInfo> connections) {
|
||||
connections.removeIf(c -> !isDataSourceAccessible(c.getDataSourceContainer()));
|
||||
}
|
||||
@@ -980,20 +956,41 @@ public class WebSession extends BaseWebSession
|
||||
return getWorkspace().getProjects();
|
||||
}
|
||||
|
||||
public void addSessionProject(WebProjectImpl project) {
|
||||
public void addSessionProject(@NotNull WebProjectImpl project) {
|
||||
getWorkspace().addProject(project);
|
||||
if (navigatorModel != null) {
|
||||
navigatorModel.getRoot().addProject(project, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteSessionProject(DBPProject project) {
|
||||
public void deleteSessionProject(@Nullable WebProjectImpl project) {
|
||||
getWorkspace().remoteProject((WebProjectImpl) project);
|
||||
if (navigatorModel != null) {
|
||||
navigatorModel.getRoot().removeProject(project);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSessionProject(@NotNull String projectId) throws DBException {
|
||||
super.addSessionProject(projectId);
|
||||
var rmProject = getRmController().getProject(projectId, false, false);
|
||||
createWebProject(rmProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSessionProject(@Nullable String projectId) throws DBException {
|
||||
super.removeSessionProject(projectId);
|
||||
var project = getProjectById(projectId);
|
||||
if (project == null) {
|
||||
return;
|
||||
}
|
||||
deleteSessionProject(project);
|
||||
var projectConnections = project.getDataSourceRegistry().getDataSources();
|
||||
for (DBPDataSourceContainer c : projectConnections) {
|
||||
removeConnection(new WebConnectionInfo(this, c));
|
||||
}
|
||||
}
|
||||
|
||||
@Property
|
||||
public boolean isValid() {
|
||||
return getSessionActiveTimeLeft() > 0;
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ package io.cloudbeaver.model.session;
|
||||
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSAbstractProjectEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSProjectResourceEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -55,8 +55,8 @@ public class WebSessionEventsFilter {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!subscribedProjectIds.isEmpty() && event instanceof WSAbstractProjectEvent) {
|
||||
var projectEvent = (WSAbstractProjectEvent) event;
|
||||
if (!subscribedProjectIds.isEmpty() && event instanceof WSProjectResourceEvent) {
|
||||
var projectEvent = (WSProjectResourceEvent) event;
|
||||
if (!subscribedProjectIds.contains(projectEvent.getProjectId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSDataSourceUpdatedEventHandlerImpl"/>
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSFolderUpdatedEventHandlerImpl"/>
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSRmResourceUpdatedEventHandlerImpl"/>
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSPermissionUpdatedEventHandler"/>
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSProjectUpdatedEventHandler"/>
|
||||
<eventHandler class="io.cloudbeaver.server.events.WSUserSecretEventHandlerImpl"/>
|
||||
</extension>
|
||||
|
||||
|
||||
@@ -16,9 +16,12 @@ enum CBServerEventId {
|
||||
cb_datasource_folder_updated,
|
||||
cb_datasource_folder_deleted,
|
||||
|
||||
cb_rm_resource_created
|
||||
cb_rm_resource_updated
|
||||
cb_rm_resource_deleted
|
||||
cb_rm_resource_created,
|
||||
cb_rm_resource_updated,
|
||||
cb_rm_resource_deleted,
|
||||
|
||||
cb_rm_project_added,
|
||||
cb_rm_project_removed
|
||||
}
|
||||
|
||||
# Events sent by client
|
||||
@@ -86,12 +89,26 @@ type CBSessionLogEvent implements CBServerEvent {
|
||||
topicId: CBEventTopic
|
||||
}
|
||||
|
||||
# RM project update event
|
||||
type CBProjectUpdateEvent implements CBServerEvent {
|
||||
id: CBServerEventId!
|
||||
topicId: CBEventTopic
|
||||
projectId: String!
|
||||
}
|
||||
|
||||
# Topic subscription event
|
||||
type CBTopicEvent implements CBClientEvent {
|
||||
id: CBClientEventId!
|
||||
topicId: CBEventTopic! # topic to subscribe / unsubscribe
|
||||
}
|
||||
|
||||
# Project event
|
||||
type CBProjectEvent implements CBClientEvent {
|
||||
id: CBClientEventId!
|
||||
topicId: CBEventTopic
|
||||
projectId: String!
|
||||
}
|
||||
|
||||
# Active projects event
|
||||
type CBProjectsActiveEvent implements CBClientEvent {
|
||||
id: CBClientEventId!
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.websocket.WSEventHandler;
|
||||
import org.jkiss.dbeaver.model.websocket.event.*;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Notify all active user session that project has been updated
|
||||
*/
|
||||
public abstract class WSAbstractProjectEventHandler<Event extends WSProjectEvent> implements WSEventHandler {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSupportedTopicId() {
|
||||
return WSEventTopic.PROJECTS.getTopicId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NotNull WSEvent event) {
|
||||
if (!getEventClass().isInstance(event)) {
|
||||
return;
|
||||
}
|
||||
var typedEvent = getEventClass().cast(event);
|
||||
Collection<BaseWebSession> allSessions = CBPlatform.getInstance().getSessionManager().getAllActiveSessions();
|
||||
for (var activeUserSession : allSessions) {
|
||||
if (WSWebUtils.isSessionIdEquals(activeUserSession, event.getSessionId())) {
|
||||
continue; // skip events from current session
|
||||
}
|
||||
if (!validateEvent(activeUserSession, typedEvent)) {
|
||||
getLog().debug(getSupportedTopicId() + " event '" + event.getId() + "' is not valid");
|
||||
continue;
|
||||
}
|
||||
getLog().debug(getSupportedTopicId() + " event '" + event.getId() + "' handled");
|
||||
updateSessionData(activeUserSession, typedEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get logger from implementation to display the implementation class name in the log
|
||||
*/
|
||||
@NotNull
|
||||
protected abstract Log getLog();
|
||||
|
||||
@NotNull
|
||||
protected abstract Class<Event> getEventClass();
|
||||
|
||||
protected abstract void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull Event event);
|
||||
|
||||
protected boolean validateEvent(@NotNull BaseWebSession activeUserSession, @NotNull Event event) {
|
||||
return activeUserSession.isProjectAccessible(event.getProjectId()) &&
|
||||
WSEventType.valueById(event.getId()) != null;
|
||||
}
|
||||
}
|
||||
+21
-17
@@ -20,7 +20,7 @@ import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventTopic;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
|
||||
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceEvent;
|
||||
@@ -28,34 +28,38 @@ import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceEvent;
|
||||
/**
|
||||
* Notify all active user session that datasource has been updated
|
||||
*/
|
||||
public class WSDataSourceUpdatedEventHandlerImpl extends WSProjectUpdatedEventHandler {
|
||||
public class WSDataSourceUpdatedEventHandlerImpl extends WSAbstractProjectEventHandler<WSDataSourceEvent> {
|
||||
|
||||
public static final Log log = Log.getLog(WSDataSourceUpdatedEventHandlerImpl.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSupportedTopicId() {
|
||||
return WSEventTopic.DATASOURCE.getTopicId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected void updateSessionData(BaseWebSession activeUserSession, WSEvent event) {
|
||||
if (!(event instanceof WSDataSourceEvent)) {
|
||||
return;
|
||||
}
|
||||
var dsUpdateEvent = (WSDataSourceEvent) event;
|
||||
if (!activeUserSession.isProjectAccessible(dsUpdateEvent.getProjectId())) {
|
||||
return;
|
||||
}
|
||||
var eventType = WSEventType.valueById(event.getId());
|
||||
if (eventType == null) {
|
||||
return;
|
||||
}
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<WSDataSourceEvent> getEventClass() {
|
||||
return WSDataSourceEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSDataSourceEvent event) {
|
||||
var sendEvent = true;
|
||||
if (activeUserSession instanceof WebSession) {
|
||||
var webSession = (WebSession) activeUserSession;
|
||||
WebProjectImpl project = webSession.getProjectById(dsUpdateEvent.getProjectId());
|
||||
WebProjectImpl project = webSession.getProjectById(event.getProjectId());
|
||||
sendEvent = webSession.updateProjectConnection(
|
||||
project,
|
||||
dsUpdateEvent.getDataSourceIds(),
|
||||
eventType
|
||||
event.getDataSourceIds(),
|
||||
WSEventType.valueById(event.getId())
|
||||
);
|
||||
}
|
||||
if (sendEvent) {
|
||||
|
||||
+23
-12
@@ -19,7 +19,7 @@ package io.cloudbeaver.server.events;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventTopic;
|
||||
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDatasourceFolderEvent;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
@@ -27,31 +27,42 @@ import org.jkiss.utils.CommonUtils;
|
||||
/**
|
||||
* Notify all active user session that datasource has been updated
|
||||
*/
|
||||
public class WSFolderUpdatedEventHandlerImpl extends WSProjectUpdatedEventHandler {
|
||||
public class WSFolderUpdatedEventHandlerImpl extends WSAbstractProjectEventHandler<WSDatasourceFolderEvent> {
|
||||
|
||||
private static final Log log = Log.getLog(WSFolderUpdatedEventHandlerImpl.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSupportedTopicId() {
|
||||
return WSEventTopic.DATASOURCE_FOLDER.getTopicId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected void updateSessionData(BaseWebSession activeUserSession, WSEvent event) {
|
||||
if (!(event instanceof WSDatasourceFolderEvent)) {
|
||||
return;
|
||||
}
|
||||
var dsFolderUpdateEvent = (WSDatasourceFolderEvent) event;
|
||||
boolean isProjectAccessible = activeUserSession.isProjectAccessible(dsFolderUpdateEvent.getProjectId());
|
||||
if (!isProjectAccessible || CommonUtils.isEmpty(dsFolderUpdateEvent.getNodePaths())) {
|
||||
return;
|
||||
}
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<WSDatasourceFolderEvent> getEventClass() {
|
||||
return WSDatasourceFolderEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSDatasourceFolderEvent event) {
|
||||
if (activeUserSession instanceof WebSession) {
|
||||
var webSession = (WebSession) activeUserSession;
|
||||
var project = webSession.getProjectById(dsFolderUpdateEvent.getProjectId());
|
||||
var project = webSession.getProjectById(event.getProjectId());
|
||||
project.getDataSourceRegistry().refreshConfig();
|
||||
webSession.getNavigatorModel().getRoot().getProjectNode(project).getDatabases().refreshChildren();
|
||||
}
|
||||
activeUserSession.addSessionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateEvent(@NotNull BaseWebSession activeUserSession, @NotNull WSDatasourceFolderEvent event) {
|
||||
return !CommonUtils.isEmpty(event.getNodePaths()) && super.validateEvent(activeUserSession, event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* DBeaver - Universal Database Manager
|
||||
* Copyright (C) 2010-2023 DBeaver Corp and others
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.security.SMObjectPermissionsGrant;
|
||||
import org.jkiss.dbeaver.model.security.SMObjects;
|
||||
import org.jkiss.dbeaver.model.websocket.WSEventHandler;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventTopic;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSProjectUpdateEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.permissions.WSObjectPermissionEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WSPermissionUpdatedEventHandler implements WSEventHandler {
|
||||
private static final Log log = Log.getLog(WSPermissionUpdatedEventHandler.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String getSupportedTopicId() {
|
||||
return WSEventTopic.PERMISSIONS.getTopicId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NotNull WSEvent event) {
|
||||
if (!(event instanceof WSObjectPermissionEvent)) {
|
||||
return;
|
||||
}
|
||||
var permissionEvent = (WSObjectPermissionEvent) event;
|
||||
if (!SMObjects.PROJECT_OBJECT_TYPE_ID.equals(permissionEvent.getSmObjectType().getObjectType())) {
|
||||
return;
|
||||
}
|
||||
var smController = CBPlatform.getInstance().getApplication().getSecurityController();
|
||||
try {
|
||||
var projectId = permissionEvent.getObjectId();
|
||||
var permissionGrants = smController.getObjectPermissionGrants(projectId, permissionEvent.getSmObjectType());
|
||||
var subjectsWithProjectAccess = permissionGrants.stream()
|
||||
.map(SMObjectPermissionsGrant::getSubjectId)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
log.debug(getSupportedTopicId() + " event handled");
|
||||
|
||||
Collection<BaseWebSession> allSessions = CBPlatform.getInstance().getSessionManager().getAllActiveSessions();
|
||||
for (var activeUserSession : allSessions) {
|
||||
if (WSWebUtils.isSessionIdEquals(activeUserSession, event.getSessionId())) {
|
||||
continue;
|
||||
}
|
||||
var user = activeUserSession.getUserContext().getUser();
|
||||
if (user == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var userSubjects = new HashSet<>(Set.of(user.getTeams()));
|
||||
userSubjects.add(user.getUserId());
|
||||
|
||||
var accessibleProjectIds = activeUserSession.getUserContext().getAccessibleProjectIds();
|
||||
var isAccessibleNow = accessibleProjectIds.contains(projectId);
|
||||
|
||||
var shouldBeAccessible = subjectsWithProjectAccess.stream().anyMatch(userSubjects::contains);
|
||||
|
||||
if (shouldBeAccessible && !isAccessibleNow) {
|
||||
// adding project to session cache
|
||||
activeUserSession.addSessionProject(projectId);
|
||||
activeUserSession.addSessionEvent(
|
||||
WSProjectUpdateEvent.create(
|
||||
event.getSessionId(),
|
||||
event.getUserId(),
|
||||
projectId
|
||||
)
|
||||
);
|
||||
} else if (!shouldBeAccessible && isAccessibleNow) {
|
||||
// removing project from session cache
|
||||
activeUserSession.removeSessionProject(projectId);
|
||||
activeUserSession.addSessionEvent(
|
||||
WSProjectUpdateEvent.delete(
|
||||
event.getSessionId(),
|
||||
event.getUserId(),
|
||||
projectId
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (DBException e) {
|
||||
log.error("Cannot get permission grants", e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+39
-19
@@ -16,38 +16,58 @@
|
||||
*/
|
||||
package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.DBWConstants;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.websocket.WSEventHandler;
|
||||
import org.jkiss.dbeaver.model.websocket.WSUtils;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
import org.jkiss.utils.CommonUtils;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventTopic;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSProjectUpdateEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
public class WSProjectUpdatedEventHandler extends WSAbstractProjectEventHandler<WSProjectUpdateEvent> {
|
||||
|
||||
/**
|
||||
* Notify all active user session that project has been updated
|
||||
*/
|
||||
public abstract class WSProjectUpdatedEventHandler implements WSEventHandler {
|
||||
private static final Log log = Log.getLog(WSProjectUpdatedEventHandler.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public abstract String getSupportedTopicId();
|
||||
public String getSupportedTopicId() {
|
||||
return WSEventTopic.PROJECTS.getTopicId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<WSProjectUpdateEvent> getEventClass() {
|
||||
return WSProjectUpdateEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NotNull WSEvent event) {
|
||||
log.debug(getSupportedTopicId() + " event handled");
|
||||
Collection<BaseWebSession> allSessions = CBPlatform.getInstance().getSessionManager().getAllActiveSessions();
|
||||
for (var activeUserSession : allSessions) {
|
||||
if (WSWebUtils.isSessionIdEquals(activeUserSession, event.getSessionId())) {
|
||||
continue;
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSProjectUpdateEvent event) {
|
||||
var eventId = event.getId();
|
||||
var projectId = event.getProjectId();
|
||||
try {
|
||||
if (eventId.equals(WSEventType.RM_PROJECT_ADDED.getEventId())) {
|
||||
activeUserSession.addSessionProject(projectId);
|
||||
log.info("Project '" + projectId + "' added to '" + activeUserSession.getSessionId() + "' session");
|
||||
} else if (eventId.equals(WSEventType.RM_PROJECT_REMOVED.getEventId())) {
|
||||
activeUserSession.removeSessionProject(projectId);
|
||||
log.info("Project '" + projectId + "' removed from '" + activeUserSession.getSessionId() + "' session");
|
||||
}
|
||||
updateSessionData(activeUserSession, event);
|
||||
activeUserSession.addSessionEvent(event);
|
||||
} catch (DBException e) {
|
||||
log.warn("Failed to handle project lifecycle event", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void updateSessionData(BaseWebSession activeUserSession, WSEvent event);
|
||||
@Override
|
||||
protected boolean validateEvent(@NotNull BaseWebSession activeUserSession, @NotNull WSProjectUpdateEvent event) {
|
||||
return event.getId().equals(WSEventType.RM_PROJECT_REMOVED.getEventId()) ||
|
||||
activeUserSession.getUserContext().hasPermission(DBWConstants.PERMISSION_ADMIN);
|
||||
}
|
||||
}
|
||||
|
||||
+25
-26
@@ -22,10 +22,10 @@ import io.cloudbeaver.WebProjectImpl;
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.rm.RMEvent;
|
||||
import org.jkiss.dbeaver.model.rm.RMEventManager;
|
||||
import org.jkiss.dbeaver.model.rm.RMResource;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventTopic;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventType;
|
||||
import org.jkiss.dbeaver.model.websocket.event.resource.WSResourceUpdatedEvent;
|
||||
@@ -36,8 +36,9 @@ import java.util.List;
|
||||
/**
|
||||
* Notify all active user session that rm resource has been updated
|
||||
*/
|
||||
public class WSRmResourceUpdatedEventHandlerImpl extends WSProjectUpdatedEventHandler {
|
||||
public class WSRmResourceUpdatedEventHandlerImpl extends WSAbstractProjectEventHandler<WSResourceUpdatedEvent> {
|
||||
|
||||
private static final Log log = Log.getLog(WSRmResourceUpdatedEventHandlerImpl.class);
|
||||
private static final Gson gson = new GsonBuilder().create();
|
||||
|
||||
@NotNull
|
||||
@@ -46,33 +47,31 @@ public class WSRmResourceUpdatedEventHandlerImpl extends WSProjectUpdatedEventHa
|
||||
return WSEventTopic.RM_SCRIPTS.getTopicId();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected void updateSessionData(BaseWebSession activeUserSession, WSEvent event) {
|
||||
if (!(event instanceof WSResourceUpdatedEvent)) {
|
||||
return;
|
||||
}
|
||||
var resourceUpdateEvent = (WSResourceUpdatedEvent) event;
|
||||
String projectId = resourceUpdateEvent.getProjectId();
|
||||
if (!activeUserSession.isProjectAccessible(projectId)) {
|
||||
return;
|
||||
}
|
||||
if (resourceUpdateEvent.getResourcePath() == null) {
|
||||
return;
|
||||
}
|
||||
Object parsedResourcePath = resourceUpdateEvent.getResourceParsedPath();
|
||||
RMResource[] resourceParsedPath;
|
||||
if (parsedResourcePath instanceof RMResource[]) {
|
||||
resourceParsedPath = (RMResource[]) parsedResourcePath;
|
||||
} else {
|
||||
resourceParsedPath = gson.fromJson(gson.toJson(parsedResourcePath), RMResource[].class);
|
||||
}
|
||||
var eventType = WSEventType.valueById(resourceUpdateEvent.getId());
|
||||
if (eventType == null) {
|
||||
return;
|
||||
}
|
||||
protected Log getLog() {
|
||||
return log;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<WSResourceUpdatedEvent> getEventClass() {
|
||||
return WSResourceUpdatedEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateSessionData(@NotNull BaseWebSession activeUserSession, @NotNull WSResourceUpdatedEvent event) {
|
||||
if (activeUserSession instanceof WebSession) {
|
||||
var parsedResourcePath = event.getResourceParsedPath();
|
||||
var resourceParsedPath = parsedResourcePath instanceof RMResource[]
|
||||
? (RMResource[]) parsedResourcePath
|
||||
: gson.fromJson(gson.toJson(parsedResourcePath), RMResource[].class);
|
||||
var webSession = (WebSession) activeUserSession;
|
||||
acceptChangesInNavigatorTree(eventType, resourceParsedPath, webSession.getProjectById(projectId));
|
||||
acceptChangesInNavigatorTree(
|
||||
WSEventType.valueById(event.getId()),
|
||||
resourceParsedPath,
|
||||
webSession.getProjectById(event.getProjectId())
|
||||
);
|
||||
}
|
||||
activeUserSession.addSessionEvent(event);
|
||||
}
|
||||
|
||||
+17
-1
@@ -18,20 +18,26 @@ package io.cloudbeaver.server.events;
|
||||
|
||||
import io.cloudbeaver.model.session.BaseWebSession;
|
||||
import io.cloudbeaver.model.session.WebSession;
|
||||
import io.cloudbeaver.server.CBPlatform;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.Log;
|
||||
import org.jkiss.dbeaver.model.websocket.WSEventHandler;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSEventTopic;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSUserSecretEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.datasource.WSDataSourceProperty;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Notify all active user session that rm resource has been updated
|
||||
*/
|
||||
public class WSUserSecretEventHandlerImpl extends WSProjectUpdatedEventHandler {
|
||||
public class WSUserSecretEventHandlerImpl implements WSEventHandler {
|
||||
|
||||
private static final Log log = Log.getLog(WSUserSecretEventHandlerImpl.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -40,6 +46,16 @@ public class WSUserSecretEventHandlerImpl extends WSProjectUpdatedEventHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleEvent(@NotNull WSEvent event) {
|
||||
Collection<BaseWebSession> allSessions = CBPlatform.getInstance().getSessionManager().getAllActiveSessions();
|
||||
for (var activeUserSession : allSessions) {
|
||||
if (WSWebUtils.isSessionIdEquals(activeUserSession, event.getSessionId())) {
|
||||
continue; // skip events from current session
|
||||
}
|
||||
updateSessionData(activeUserSession, event);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateSessionData(BaseWebSession activeUserSession, WSEvent event) {
|
||||
if (!(event instanceof WSUserSecretEvent && activeUserSession instanceof WebSession)) {
|
||||
return;
|
||||
|
||||
+25
-2
@@ -23,16 +23,18 @@ import io.cloudbeaver.service.rm.DBWServiceRM;
|
||||
import io.cloudbeaver.service.rm.model.RMProjectPermissions;
|
||||
import io.cloudbeaver.service.rm.model.RMSubjectProjectPermissions;
|
||||
import io.cloudbeaver.service.security.SMUtils;
|
||||
import io.cloudbeaver.utils.WebAppUtils;
|
||||
import io.cloudbeaver.utils.WebEventUtils;
|
||||
import org.jkiss.code.NotNull;
|
||||
import org.jkiss.code.Nullable;
|
||||
import org.jkiss.dbeaver.DBException;
|
||||
import org.jkiss.dbeaver.model.app.DBPProject;
|
||||
import org.jkiss.dbeaver.model.rm.RMController;
|
||||
import org.jkiss.dbeaver.model.rm.RMProject;
|
||||
import org.jkiss.dbeaver.model.rm.RMResource;
|
||||
import org.jkiss.dbeaver.model.security.*;
|
||||
import org.jkiss.dbeaver.model.websocket.WSConstants;
|
||||
import org.jkiss.dbeaver.model.websocket.event.WSProjectUpdateEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.permissions.WSObjectPermissionEvent;
|
||||
import org.jkiss.dbeaver.model.websocket.event.resource.WSResourceProperty;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -255,6 +257,9 @@ public class WebServiceRM implements DBWServiceRM {
|
||||
try {
|
||||
RMProject rmProject = getResourceController(session).createProject(name, description);
|
||||
session.createWebProject(rmProject);
|
||||
WebAppUtils.getWebApplication().getEventController().addEvent(
|
||||
WSProjectUpdateEvent.create(session.getSessionId(), session.getUserId(), rmProject.getId())
|
||||
);
|
||||
return rmProject;
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Error creating project", e);
|
||||
@@ -264,9 +269,12 @@ public class WebServiceRM implements DBWServiceRM {
|
||||
@Override
|
||||
public boolean deleteProject(@NotNull WebSession session, @NotNull String projectId) throws DBWebException {
|
||||
try {
|
||||
DBPProject project = session.getProjectById(projectId);
|
||||
var project = session.getProjectById(projectId);
|
||||
getResourceController(session).deleteProject(projectId);
|
||||
session.deleteSessionProject(project);
|
||||
WebAppUtils.getWebApplication().getEventController().addEvent(
|
||||
WSProjectUpdateEvent.delete(session.getSessionId(), session.getUserId(), projectId)
|
||||
);
|
||||
return true;
|
||||
} catch (DBException e) {
|
||||
throw new DBWebException("Error deleting project", e);
|
||||
@@ -301,12 +309,26 @@ public class WebServiceRM implements DBWServiceRM {
|
||||
webSession.getUserId()
|
||||
);
|
||||
}
|
||||
addProjectPermissionsUpdatedEvent(webSession, projectId);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
throw new DBWebException("Error granting project permissions", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addProjectPermissionsUpdatedEvent(
|
||||
@NotNull WebSession webSession,
|
||||
@NotNull String projectId
|
||||
) {
|
||||
var event = WSObjectPermissionEvent.update(
|
||||
webSession.getUserContext().getSmSessionId(),
|
||||
webSession.getUserId(),
|
||||
SMObjects.PROJECT,
|
||||
projectId
|
||||
);
|
||||
webSession.getApplication().getEventController().addEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setSubjectProjectPermissions(
|
||||
@NotNull WebSession webSession,
|
||||
@@ -325,6 +347,7 @@ public class WebServiceRM implements DBWServiceRM {
|
||||
permissions,
|
||||
webSession.getUserId()
|
||||
);
|
||||
addProjectPermissionsUpdatedEvent(webSession, projectId);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
*/
|
||||
|
||||
import { injectable } from '@cloudbeaver/core-di';
|
||||
import { SessionEventSource, TopicEventHandler, ISessionEvent, ClientEventId, SessionEventTopic, IBaseServerEvent, SessionEventId } from '@cloudbeaver/core-root';
|
||||
import type { CbProjectsActiveEvent } from '@cloudbeaver/core-sdk';
|
||||
import { SessionEventSource, TopicEventHandler, ISessionEvent, ClientEventId, SessionEventTopic, SessionEventId } from '@cloudbeaver/core-root';
|
||||
import type { CbProjectsActiveEvent, CbProjectUpdateEvent as IProjectInfoEvent } from '@cloudbeaver/core-sdk';
|
||||
import { isArraysEqual } from '@cloudbeaver/core-utils';
|
||||
|
||||
export type IProjectInfoEvent = IBaseServerEvent<SessionEventId, SessionEventTopic>;
|
||||
export { IProjectInfoEvent };
|
||||
|
||||
@injectable()
|
||||
export class ProjectInfoEventHandler
|
||||
@@ -38,7 +38,7 @@ export class ProjectInfoEventHandler
|
||||
this.lastActiveProjects = projectIds;
|
||||
}
|
||||
|
||||
map(event: ISessionEvent): IProjectInfoEvent {
|
||||
map(event: any): IProjectInfoEvent {
|
||||
return event;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,13 @@ import { computed, makeObservable } from 'mobx';
|
||||
import { UserDataService, UserInfoResource } from '@cloudbeaver/core-authentication';
|
||||
import { Dependency, injectable } from '@cloudbeaver/core-di';
|
||||
import { Executor, ExecutorInterrupter, IExecutor, ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { CachedMapAllKey, resourceKeyList } from '@cloudbeaver/core-sdk';
|
||||
import { DataSynchronizationService, ServerEventId } from '@cloudbeaver/core-root';
|
||||
import { CachedMapAllKey, resourceKeyList, ResourceKeyUtils } from '@cloudbeaver/core-sdk';
|
||||
import { NavigationService } from '@cloudbeaver/core-ui';
|
||||
import { isArraysEqual } from '@cloudbeaver/core-utils';
|
||||
|
||||
import { activeProjectsContext } from './activeProjectsContext';
|
||||
import { ProjectInfoEventHandler } from './ProjectInfoEventHandler';
|
||||
import { IProjectInfoEvent, ProjectInfoEventHandler } from './ProjectInfoEventHandler';
|
||||
import { ProjectInfo, ProjectInfoResource } from './ProjectInfoResource';
|
||||
|
||||
interface IActiveProjectData {
|
||||
@@ -95,6 +96,7 @@ export class ProjectsService extends Dependency {
|
||||
private readonly userInfoResource: UserInfoResource,
|
||||
private readonly userDataService: UserDataService,
|
||||
private readonly projectInfoEventHandler: ProjectInfoEventHandler,
|
||||
private readonly dataSynchronizationService: DataSynchronizationService,
|
||||
navigationService: NavigationService
|
||||
) {
|
||||
super();
|
||||
@@ -127,6 +129,34 @@ export class ProjectsService extends Dependency {
|
||||
this.projectInfoEventHandler.setActiveProjects(this.activeProjects.map(project => project.id));
|
||||
});
|
||||
|
||||
this.projectInfoResource.onItemDelete.addHandler(async data => {
|
||||
const ids = ResourceKeyUtils.toArray(data);
|
||||
const wasActive = ids.some(id => this.activeProjectIds.includes(id));
|
||||
if (wasActive) {
|
||||
await this.setActiveProjects(this.activeProjects.filter(project => !ids.includes(project.id)));
|
||||
}
|
||||
});
|
||||
|
||||
this.projectInfoEventHandler.onEvent<IProjectInfoEvent>(ServerEventId.CbRmProjectAdded, () => {
|
||||
this.projectInfoResource.markOutdated();
|
||||
}, undefined, this.projectInfoResource);
|
||||
|
||||
this.projectInfoEventHandler.onEvent<IProjectInfoEvent>(ServerEventId.CbRmProjectRemoved, key => {
|
||||
if (this.activeProjectIds.includes(key.projectId)) {
|
||||
const project = this.projectInfoResource.get(key.projectId);
|
||||
|
||||
this.dataSynchronizationService
|
||||
.requestSynchronization('project', project?.name ?? '')
|
||||
.then(state => {
|
||||
if (state) {
|
||||
this.projectInfoResource.delete(key.projectId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.projectInfoResource.delete(key.projectId);
|
||||
}
|
||||
}, undefined, this.projectInfoResource);
|
||||
|
||||
makeObservable(this, {
|
||||
userProject: computed,
|
||||
defaultProject: computed,
|
||||
|
||||
@@ -205,6 +205,18 @@ export enum CbEventTopic {
|
||||
CbSessionLog = 'cb_session_log'
|
||||
}
|
||||
|
||||
export interface CbProjectEvent extends CbClientEvent {
|
||||
id: CbClientEventId;
|
||||
projectId: Scalars['String'];
|
||||
topicId?: Maybe<CbEventTopic>;
|
||||
}
|
||||
|
||||
export interface CbProjectUpdateEvent extends CbServerEvent {
|
||||
id: CbServerEventId;
|
||||
projectId: Scalars['String'];
|
||||
topicId?: Maybe<CbEventTopic>;
|
||||
}
|
||||
|
||||
export interface CbProjectsActiveEvent extends CbClientEvent {
|
||||
id: CbClientEventId;
|
||||
projectIds: Array<Scalars['String']>;
|
||||
@@ -231,6 +243,8 @@ export enum CbServerEventId {
|
||||
CbDatasourceFolderDeleted = 'cb_datasource_folder_deleted',
|
||||
CbDatasourceFolderUpdated = 'cb_datasource_folder_updated',
|
||||
CbDatasourceUpdated = 'cb_datasource_updated',
|
||||
CbRmProjectAdded = 'cb_rm_project_added',
|
||||
CbRmProjectRemoved = 'cb_rm_project_removed',
|
||||
CbRmResourceCreated = 'cb_rm_resource_created',
|
||||
CbRmResourceDeleted = 'cb_rm_resource_deleted',
|
||||
CbRmResourceUpdated = 'cb_rm_resource_updated',
|
||||
|
||||
+8
-2
@@ -14,7 +14,7 @@ import { ConnectionInfoActiveProjectKey, ConnectionInfoResource } from '@cloudbe
|
||||
import { useService } from '@cloudbeaver/core-di';
|
||||
import { NotificationService } from '@cloudbeaver/core-events';
|
||||
import { ISyncExecutor, SyncExecutor } from '@cloudbeaver/core-executor';
|
||||
import { type NavNode, NavNodeInfoResource, NavTreeResource } from '@cloudbeaver/core-navigation-tree';
|
||||
import { type NavNode, NavNodeInfoResource, NavTreeResource, ROOT_NODE_PATH } 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';
|
||||
@@ -81,7 +81,7 @@ export interface IElementsTreeOptions {
|
||||
isGroup?: (node: NavNode) => boolean;
|
||||
customSelect?: (node: NavNode, multiple: boolean, nested: boolean) => Promise<void> | void;
|
||||
beforeSelect?: (node: NavNode, multiple: boolean, nested: boolean) => Promise<void> | void;
|
||||
customSelectReset?: ()=> Promise<void> | void;
|
||||
customSelectReset?: () => Promise<void> | void;
|
||||
}
|
||||
|
||||
interface IOptions extends IElementsTreeOptions {
|
||||
@@ -125,6 +125,7 @@ export interface IElementsTree extends ILoadableState {
|
||||
|
||||
export function useElementsTree(options: IOptions): IElementsTree {
|
||||
const projectsService = useService(ProjectsService);
|
||||
const projectInfoResource = useService(ProjectInfoResource);
|
||||
const notificationService = useService(NotificationService);
|
||||
const navNodeInfoResource = useService(NavNodeInfoResource);
|
||||
const navTreeResource = useService(NavTreeResource);
|
||||
@@ -618,6 +619,11 @@ export function useElementsTree(options: IOptions): IElementsTree {
|
||||
}],
|
||||
});
|
||||
|
||||
useExecutor({
|
||||
executor: projectInfoResource.onDataOutdated,
|
||||
handlers: [() => navTreeResource.markOutdated(ROOT_NODE_PATH)],
|
||||
});
|
||||
|
||||
useExecutor({
|
||||
executor: navTreeResource.onItemUpdate,
|
||||
handlers: [function exitFolder(key) {
|
||||
|
||||
Reference in New Issue
Block a user