diff --git a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java
index 73f1f0b61b..0c4f02e26c 100644
--- a/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java
+++ b/server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/session/WebSession.java
@@ -132,6 +132,12 @@ public WebSession(
this.lastAccessTime = this.createTime;
setLocale(CommonUtils.toString(httpSession.getAttribute(ATTR_LOCALE), this.locale));
this.sessionHandlers = sessionHandlers;
+ //force authorization of anonymous session to avoid access error,
+ //because before authorization could be called by any request,
+ //but now 'updateInfo' is called only in special requests,
+ //and the order of requests is not guaranteed.
+ //look at CB-4747
+ refreshSessionAuth();
}
@Override
@@ -521,6 +527,7 @@ public synchronized void updateInfo(
HttpServletRequest request,
HttpServletResponse response
) throws DBWebException {
+ log.debug("Update session lifetime " + getSessionId() + " for user " + getUserId());
touchSession();
HttpSession httpSession = request.getSession();
this.lastRemoteAddr = request.getRemoteAddr();
diff --git a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls
index e0b7e6ae7b..b393c48824 100644
--- a/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls
+++ b/server/bundles/io.cloudbeaver.server/schema/service.core.graphqls
@@ -566,7 +566,9 @@ extend type Mutation {
closeSession: Boolean
# Refreshes session on server and returns its state
- touchSession: Boolean
+ touchSession: Boolean @deprecated(reason: "use updateSession instead")
+ # Refreshes session on server and returns session state
+ updateSession: SessionInfo! @since(version: "24.0.0")
# Refresh session connection list
refreshSessionConnections: Boolean
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java
index 65007f34b9..e684f44669 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/DBWServiceCore.java
@@ -90,9 +90,14 @@ WebSession openSession(
@WebAction(authRequired = false)
boolean closeSession(HttpServletRequest request) throws DBWebException;
+ @Deprecated
@WebAction(authRequired = false)
boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse servletResponse) throws DBWebException;
+ @WebAction(authRequired = false)
+ WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
+ throws DBWebException;
+
@WebAction(authRequired = false)
boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException;
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java
index 76f2e718cd..7c55eb2c37 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/WebServiceBindingCore.java
@@ -99,6 +99,8 @@ public void bindWiring(DBWBindingContext model) throws DBWebException {
.dataFetcher("closeSession", env -> getService(env).closeSession(GraphQLEndpoint.getServletRequest(env)))
.dataFetcher("touchSession", env -> getService(env).touchSession(
GraphQLEndpoint.getServletRequest(env), GraphQLEndpoint.getServletResponse(env)))
+ .dataFetcher("updateSession", env -> getService(env).updateSession(
+ GraphQLEndpoint.getServletRequest(env), GraphQLEndpoint.getServletResponse(env)))
.dataFetcher("refreshSessionConnections", env -> getService(env).refreshSessionConnections(
GraphQLEndpoint.getServletRequest(env), GraphQLEndpoint.getServletResponse(env)))
.dataFetcher("changeSessionLanguage", env -> getService(env).changeSessionLanguage(getWebSession(env), env.getArgument("locale")))
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java
index 5707ac37ca..ad7eec7b06 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/core/impl/WebServiceCore.java
@@ -29,6 +29,7 @@
import io.cloudbeaver.server.CBPlatform;
import io.cloudbeaver.service.core.DBWServiceCore;
import io.cloudbeaver.service.security.SMUtils;
+import io.cloudbeaver.service.session.WebSessionManager;
import io.cloudbeaver.utils.WebConnectionFolderUtils;
import io.cloudbeaver.utils.WebDataSourceUtils;
import io.cloudbeaver.utils.WebEventUtils;
@@ -285,6 +286,14 @@ public boolean touchSession(@NotNull HttpServletRequest request, @NotNull HttpSe
return CBPlatform.getInstance().getSessionManager().touchSession(request, response);
}
+ @Override
+ public WebSession updateSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response)
+ throws DBWebException {
+ WebSessionManager sessionManager = CBPlatform.getInstance().getSessionManager();
+ sessionManager.touchSession(request, response);
+ return sessionManager.getWebSession(request, response, true);
+ }
+
@Override
public boolean refreshSessionConnections(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response) throws DBWebException {
WebSession session = CBPlatform.getInstance().getSessionManager().getWebSession(request, response);
diff --git a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java
index c481e00fd7..6704c92ffd 100644
--- a/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java
+++ b/server/bundles/io.cloudbeaver.server/src/io/cloudbeaver/service/session/WebSessionManager.java
@@ -93,12 +93,11 @@ public WebSession getWebSession(@NotNull HttpServletRequest request,
}
@NotNull
- public WebSession getWebSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, boolean errorOnNoFound) throws DBWebException {
- return getWebSession(request, response, true, errorOnNoFound);
- }
-
- @NotNull
- public WebSession getWebSession(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, boolean updateInfo, boolean errorOnNoFound) throws DBWebException {
+ public WebSession getWebSession(
+ @NotNull HttpServletRequest request,
+ @NotNull HttpServletResponse response,
+ boolean errorOnNoFound
+ ) throws DBWebException {
HttpSession httpSession = request.getSession(true);
String sessionId = httpSession.getId();
WebSession webSession;
@@ -139,13 +138,6 @@ public WebSession getWebSession(@NotNull HttpServletRequest request, @NotNull Ht
throw new DBWebException("Unexpected session type: " + baseWebSession.getClass().getName());
}
webSession = (WebSession) baseWebSession;
- if (updateInfo) {
- // Update only once per request
- if (!CommonUtils.toBoolean(request.getAttribute("sessionUpdated"))) {
- webSession.updateInfo(request, response);
- request.setAttribute("sessionUpdated", true);
- }
- }
}
}
@@ -328,16 +320,21 @@ public WebHeadlessSession getHeadlessSession(HttpServletRequest request, boolean
*/
public void sendSessionsStates() {
synchronized (sessionMap) {
- for (var session : sessionMap.values()) {
- if (session instanceof WebHeadlessSession) {
- continue;
- }
- try {
- session.addSessionEvent(new WSSessionStateEvent(session.getRemainingTime(), session.isValid()));
- } catch (Exception e) {
- log.error("Failed to refresh session state: " + session.getSessionId(), e);
- }
- }
+ sessionMap.values()
+ .parallelStream()
+ .filter(session -> {
+ if (session instanceof WebSession webSession) {
+ return webSession.isAuthorizedInSecurityManager();
+ }
+ return false;
+ })
+ .forEach(session -> {
+ try {
+ session.addSessionEvent(new WSSessionStateEvent(session.getRemainingTime(), session.isValid()));
+ } catch (Exception e) {
+ log.error("Failed to refresh session state: " + session.getSessionId(), e);
+ }
+ });
}
}
diff --git a/server/drivers/postgresql/pom.xml b/server/drivers/postgresql/pom.xml
index 2efa74ee8a..a0e12cbf1c 100644
--- a/server/drivers/postgresql/pom.xml
+++ b/server/drivers/postgresql/pom.xml
@@ -18,7 +18,7 @@
org.postgresql
postgresql
- 42.5.2
+ 42.7.2
net.postgis
diff --git a/webapp/packages/core-administration/package.json b/webapp/packages/core-administration/package.json
index a8208e3e31..ab3efce199 100644
--- a/webapp/packages/core-administration/package.json
+++ b/webapp/packages/core-administration/package.json
@@ -36,6 +36,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts b/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts
index e01defca4a..6fadda2735 100644
--- a/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts
+++ b/webapp/packages/core-administration/src/AdministrationSettingsService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -37,6 +38,7 @@ const app = createApp(
// coreRoutingManifest,
// coreThemingManifest,
coreLocalizationManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/core-administration/tsconfig.json b/webapp/packages/core-administration/tsconfig.json
index b71c4bdc46..3a930b8e3a 100644
--- a/webapp/packages/core-administration/tsconfig.json
+++ b/webapp/packages/core-administration/tsconfig.json
@@ -9,6 +9,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-data-context/tsconfig.json"
},
diff --git a/webapp/packages/core-app/package.json b/webapp/packages/core-app/package.json
index cd38d98b18..562afd0017 100644
--- a/webapp/packages/core-app/package.json
+++ b/webapp/packages/core-app/package.json
@@ -18,6 +18,7 @@
},
"dependencies": {
"@cloudbeaver/core-blocks": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-di": "~0.1.0",
"@cloudbeaver/core-executor": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
diff --git a/webapp/packages/core-app/src/Body.tsx b/webapp/packages/core-app/src/Body.tsx
index 6f7849ad28..7de2d8538f 100644
--- a/webapp/packages/core-app/src/Body.tsx
+++ b/webapp/packages/core-app/src/Body.tsx
@@ -21,6 +21,7 @@ import { useAppVersion } from '@cloudbeaver/core-version';
import style from './Body.m.css';
import { useAppHeight } from './useAppHeight';
+import { useClientActivity } from './useClientActivity';
export const Body = observer(function Body() {
// const serverConfigLoader = useResource(Body, ServerConfigResource, undefined);
@@ -44,6 +45,7 @@ export const Body = observer(function Body() {
});
useAppHeight();
+ useClientActivity();
return (
diff --git a/webapp/packages/core-app/src/useClientActivity.ts b/webapp/packages/core-app/src/useClientActivity.ts
new file mode 100644
index 0000000000..55ac97865e
--- /dev/null
+++ b/webapp/packages/core-app/src/useClientActivity.ts
@@ -0,0 +1,46 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2024 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 { useEffect } from 'react';
+
+import { ClientActivityService } from '@cloudbeaver/core-client-activity';
+import { useService } from '@cloudbeaver/core-di';
+import { throttle } from '@cloudbeaver/core-utils';
+
+const UPDATE_THROTTLE = 300;
+
+export function useClientActivity() {
+ const clientActivityService = useService(ClientActivityService);
+
+ const updateActivity = throttle(function updateActivity() {
+ clientActivityService.updateActivity();
+ }, UPDATE_THROTTLE);
+
+ function subscribeEvents() {
+ document.addEventListener('mousemove', updateActivity);
+ document.addEventListener('click', updateActivity);
+ document.addEventListener('keydown', updateActivity);
+ document.addEventListener('scroll', updateActivity);
+ document.addEventListener('touchstart', updateActivity);
+ }
+
+ function unsubscribeEvents() {
+ document.removeEventListener('mousemove', updateActivity);
+ document.removeEventListener('click', updateActivity);
+ document.removeEventListener('keydown', updateActivity);
+ document.removeEventListener('scroll', updateActivity);
+ document.removeEventListener('touchstart', updateActivity);
+ }
+
+ useEffect(() => {
+ subscribeEvents();
+
+ return () => {
+ unsubscribeEvents();
+ };
+ }, []);
+}
diff --git a/webapp/packages/core-app/tsconfig.json b/webapp/packages/core-app/tsconfig.json
index a8bdc73634..0f575e5654 100644
--- a/webapp/packages/core-app/tsconfig.json
+++ b/webapp/packages/core-app/tsconfig.json
@@ -9,6 +9,9 @@
{
"path": "../core-blocks/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/core-authentication/package.json b/webapp/packages/core-authentication/package.json
index 0779571fd9..b192ebc797 100644
--- a/webapp/packages/core-authentication/package.json
+++ b/webapp/packages/core-authentication/package.json
@@ -35,6 +35,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/core-authentication/src/AuthSettingsService.test.ts b/webapp/packages/core-authentication/src/AuthSettingsService.test.ts
index a726605a30..2a8f059912 100644
--- a/webapp/packages/core-authentication/src/AuthSettingsService.test.ts
+++ b/webapp/packages/core-authentication/src/AuthSettingsService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -40,6 +41,7 @@ const app = createApp(
coreRoutingManifest,
coreThemingManifest,
coreLocalizationManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/core-authentication/tsconfig.json b/webapp/packages/core-authentication/tsconfig.json
index 5b1b6352b5..9b1bd78411 100644
--- a/webapp/packages/core-authentication/tsconfig.json
+++ b/webapp/packages/core-authentication/tsconfig.json
@@ -14,6 +14,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-data-context/tsconfig.json"
},
diff --git a/webapp/packages/core-blocks/package.json b/webapp/packages/core-blocks/package.json
index 21b5999970..734f2e38a4 100644
--- a/webapp/packages/core-blocks/package.json
+++ b/webapp/packages/core-blocks/package.json
@@ -40,6 +40,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/core-blocks/src/ErrorMessage.test.tsx b/webapp/packages/core-blocks/src/ErrorMessage.test.tsx
index 3fdafe2caf..c6590c4480 100644
--- a/webapp/packages/core-blocks/src/ErrorMessage.test.tsx
+++ b/webapp/packages/core-blocks/src/ErrorMessage.test.tsx
@@ -9,6 +9,7 @@ import '@testing-library/jest-dom';
import { screen } from '@testing-library/react';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -35,6 +36,7 @@ const app = createApp(
coreBrowserManifest,
coreThemingManifest,
coreLocalizationManifest,
+ coreClientActivityManifest,
);
mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/core-blocks/tsconfig.json b/webapp/packages/core-blocks/tsconfig.json
index 337afba540..44632bf437 100644
--- a/webapp/packages/core-blocks/tsconfig.json
+++ b/webapp/packages/core-blocks/tsconfig.json
@@ -12,6 +12,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/core-bootstrap/package.json b/webapp/packages/core-bootstrap/package.json
index cd4d661c91..e58afffc61 100644
--- a/webapp/packages/core-bootstrap/package.json
+++ b/webapp/packages/core-bootstrap/package.json
@@ -24,6 +24,7 @@
"@cloudbeaver/core-browser": "~0.1.0",
"@cloudbeaver/core-browser-cookies": "~0.1.0",
"@cloudbeaver/core-browser-settings": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-connections": "~0.1.0",
"@cloudbeaver/core-di": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
diff --git a/webapp/packages/core-bootstrap/src/manifest.ts b/webapp/packages/core-bootstrap/src/manifest.ts
index 1c9e7567cd..51fb31ba3b 100644
--- a/webapp/packages/core-bootstrap/src/manifest.ts
+++ b/webapp/packages/core-bootstrap/src/manifest.ts
@@ -12,6 +12,7 @@ import { coreBlocksManifest } from '@cloudbeaver/core-blocks';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
import { coreBrowserCookiesManifest } from '@cloudbeaver/core-browser-cookies';
import { coreBrowserSettingsManifest } from '@cloudbeaver/core-browser-settings';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreConnectionsManifest } from '@cloudbeaver/core-connections';
import { coreDIManifest, PluginManifest } from '@cloudbeaver/core-di';
import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
@@ -74,5 +75,6 @@ export const coreManifests: PluginManifest[] = [
coreDialogsManifest,
resourceManagerManifest,
coreAppManifest,
+ coreClientActivityManifest,
coreNavigationTree,
];
diff --git a/webapp/packages/core-bootstrap/tsconfig.json b/webapp/packages/core-bootstrap/tsconfig.json
index 26e6ec4dc5..fdb992e6d4 100644
--- a/webapp/packages/core-bootstrap/tsconfig.json
+++ b/webapp/packages/core-bootstrap/tsconfig.json
@@ -27,6 +27,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-connections/tsconfig.json"
},
diff --git a/webapp/packages/core-browser-settings/package.json b/webapp/packages/core-browser-settings/package.json
index 7fc54220d5..d0fddf81ef 100644
--- a/webapp/packages/core-browser-settings/package.json
+++ b/webapp/packages/core-browser-settings/package.json
@@ -27,6 +27,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
"@cloudbeaver/core-product": "~0.1.0",
diff --git a/webapp/packages/core-browser-settings/src/BrowserSettingsService.test.ts b/webapp/packages/core-browser-settings/src/BrowserSettingsService.test.ts
index d8fcf540f3..2049e9aff6 100644
--- a/webapp/packages/core-browser-settings/src/BrowserSettingsService.test.ts
+++ b/webapp/packages/core-browser-settings/src/BrowserSettingsService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
import { coreProductManifest } from '@cloudbeaver/core-product';
@@ -33,6 +34,7 @@ const app = createApp(
coreSDKManifest,
coreSettingsManifest,
coreLocalizationManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/core-browser-settings/tsconfig.json b/webapp/packages/core-browser-settings/tsconfig.json
index 4e8b9c2fa6..dec9a7e73a 100644
--- a/webapp/packages/core-browser-settings/tsconfig.json
+++ b/webapp/packages/core-browser-settings/tsconfig.json
@@ -14,6 +14,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/core-client-activity/.gitignore b/webapp/packages/core-client-activity/.gitignore
new file mode 100644
index 0000000000..99902db863
--- /dev/null
+++ b/webapp/packages/core-client-activity/.gitignore
@@ -0,0 +1,21 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+
+# testing
+/coverage
+
+# production
+/lib
+
+# misc
+.DS_Store
+.env*
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
diff --git a/webapp/packages/core-client-activity/package.json b/webapp/packages/core-client-activity/package.json
new file mode 100644
index 0000000000..8ac8be39f0
--- /dev/null
+++ b/webapp/packages/core-client-activity/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "@cloudbeaver/core-client-activity",
+ "sideEffects": [
+ "src/**/*.css",
+ "src/**/*.scss",
+ "public/**/*"
+ ],
+ "version": "0.1.0",
+ "description": "",
+ "license": "Apache-2.0",
+ "main": "dist/index.js",
+ "scripts": {
+ "build": "tsc -b",
+ "lint": "eslint ./src/ --ext .ts,.tsx",
+ "lint-fix": "eslint ./src/ --ext .ts,.tsx --fix",
+ "validate-dependencies": "core-cli-validate-dependencies",
+ "update-ts-references": "rimraf --glob dist && typescript-resolve-references"
+ },
+ "dependencies": {
+ "@cloudbeaver/core-di": "~0.1.0",
+ "@cloudbeaver/core-executor": "~0.1.0",
+ "mobx": "^6.12.0"
+ },
+ "peerDependencies": {},
+ "devDependencies": {
+ "typescript": "^5.3.2"
+ }
+}
diff --git a/webapp/packages/core-client-activity/src/ClientActivityService.ts b/webapp/packages/core-client-activity/src/ClientActivityService.ts
new file mode 100644
index 0000000000..73d71506b0
--- /dev/null
+++ b/webapp/packages/core-client-activity/src/ClientActivityService.ts
@@ -0,0 +1,58 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2024 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 { makeObservable, observable } from 'mobx';
+
+import { injectable } from '@cloudbeaver/core-di';
+import { Executor, IExecutor } from '@cloudbeaver/core-executor';
+
+const INACTIVE_PERIOD_TIME = 1000 * 60;
+
+@injectable()
+export class ClientActivityService {
+ private timer: ReturnType | null;
+ public isActive: boolean;
+ public onActiveStateChange: IExecutor;
+
+ constructor() {
+ this.setActivity = this.setActivity.bind(this);
+ this.updateActivity = this.updateActivity.bind(this);
+ this.resetActivity = this.resetActivity.bind(this);
+
+ this.timer = null;
+ this.isActive = false;
+ this.onActiveStateChange = new Executor();
+
+ makeObservable(this, {
+ isActive: observable,
+ });
+ }
+
+ private setActivity(value: boolean) {
+ this.isActive = value;
+ this.onActiveStateChange.execute(value);
+ }
+
+ resetActivity() {
+ this.setActivity(false);
+
+ if (this.timer) {
+ clearTimeout(this.timer);
+ this.timer = null;
+ }
+ }
+
+ updateActivity() {
+ this.setActivity(true);
+
+ if (this.timer) {
+ clearTimeout(this.timer);
+ }
+
+ this.timer = setTimeout(this.resetActivity, INACTIVE_PERIOD_TIME);
+ }
+}
diff --git a/webapp/packages/core-client-activity/src/index.ts b/webapp/packages/core-client-activity/src/index.ts
new file mode 100644
index 0000000000..b06c56627e
--- /dev/null
+++ b/webapp/packages/core-client-activity/src/index.ts
@@ -0,0 +1,2 @@
+export * from './ClientActivityService';
+export * from './manifest';
diff --git a/webapp/packages/core-client-activity/src/manifest.ts b/webapp/packages/core-client-activity/src/manifest.ts
new file mode 100644
index 0000000000..469b923fc3
--- /dev/null
+++ b/webapp/packages/core-client-activity/src/manifest.ts
@@ -0,0 +1,18 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2024 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 type { PluginManifest } from '@cloudbeaver/core-di';
+
+import { ClientActivityService } from './ClientActivityService';
+
+export const coreClientActivityManifest: PluginManifest = {
+ info: {
+ name: 'Core Client Activity',
+ },
+
+ providers: [ClientActivityService],
+};
diff --git a/webapp/packages/core-client-activity/tsconfig.json b/webapp/packages/core-client-activity/tsconfig.json
new file mode 100644
index 0000000000..df9dba157c
--- /dev/null
+++ b/webapp/packages/core-client-activity/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "extends": "../../tsconfig.base.json",
+ "compilerOptions": {
+ "rootDir": "src",
+ "outDir": "dist",
+ "tsBuildInfoFile": "dist/tsconfig.tsbuildinfo"
+ },
+ "references": [
+ {
+ "path": "../core-di/tsconfig.json"
+ },
+ {
+ "path": "../core-executor/tsconfig.json"
+ }
+ ],
+ "include": [
+ "__custom_mocks__/**/*",
+ "src/**/*",
+ "src/**/*.json",
+ "src/**/*.css",
+ "src/**/*.scss"
+ ],
+ "exclude": [
+ "**/node_modules",
+ "lib/**/*",
+ "dist/**/*"
+ ]
+}
diff --git a/webapp/packages/core-events/package.json b/webapp/packages/core-events/package.json
index ca4b248483..4573e974a6 100644
--- a/webapp/packages/core-events/package.json
+++ b/webapp/packages/core-events/package.json
@@ -29,6 +29,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
"@cloudbeaver/core-product": "~0.1.0",
diff --git a/webapp/packages/core-events/src/EventsSettingsService.test.ts b/webapp/packages/core-events/src/EventsSettingsService.test.ts
index 6b5b9237ef..667d98c0c1 100644
--- a/webapp/packages/core-events/src/EventsSettingsService.test.ts
+++ b/webapp/packages/core-events/src/EventsSettingsService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
import { coreProductManifest } from '@cloudbeaver/core-product';
@@ -33,6 +34,7 @@ const app = createApp(
coreProductManifest,
coreRootManifest,
coreSDKManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/core-events/tsconfig.json b/webapp/packages/core-events/tsconfig.json
index dff6765528..7e5ca46969 100644
--- a/webapp/packages/core-events/tsconfig.json
+++ b/webapp/packages/core-events/tsconfig.json
@@ -9,6 +9,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/core-navigation-tree/package.json b/webapp/packages/core-navigation-tree/package.json
index 2365bad928..6ff5dbe7e6 100644
--- a/webapp/packages/core-navigation-tree/package.json
+++ b/webapp/packages/core-navigation-tree/package.json
@@ -38,6 +38,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/core-navigation-tree/src/NavTreeSettingsService.test.ts b/webapp/packages/core-navigation-tree/src/NavTreeSettingsService.test.ts
index 0992fc2e5f..fd75fb9af1 100644
--- a/webapp/packages/core-navigation-tree/src/NavTreeSettingsService.test.ts
+++ b/webapp/packages/core-navigation-tree/src/NavTreeSettingsService.test.ts
@@ -11,6 +11,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -50,6 +51,7 @@ const app = createApp(
coreProjectsManifest,
coreUIManifest,
coreViewManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/core-navigation-tree/tsconfig.json b/webapp/packages/core-navigation-tree/tsconfig.json
index 8678d53fbf..c126841b41 100644
--- a/webapp/packages/core-navigation-tree/tsconfig.json
+++ b/webapp/packages/core-navigation-tree/tsconfig.json
@@ -18,6 +18,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-data-context/tsconfig.json"
},
diff --git a/webapp/packages/core-root/package.json b/webapp/packages/core-root/package.json
index 8d9f615cec..9b8440fc73 100644
--- a/webapp/packages/core-root/package.json
+++ b/webapp/packages/core-root/package.json
@@ -17,6 +17,7 @@
"update-ts-references": "rimraf --glob dist && typescript-resolve-references"
},
"dependencies": {
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-di": "~0.1.0",
"@cloudbeaver/core-executor": "~0.1.0",
"@cloudbeaver/core-resource": "~0.1.0",
diff --git a/webapp/packages/core-root/src/SessionActivityService.ts b/webapp/packages/core-root/src/SessionActivityService.ts
new file mode 100644
index 0000000000..cd6a5dc144
--- /dev/null
+++ b/webapp/packages/core-root/src/SessionActivityService.ts
@@ -0,0 +1,43 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2024 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 { ClientActivityService } from '@cloudbeaver/core-client-activity';
+import { Dependency, injectable } from '@cloudbeaver/core-di';
+
+import { SessionResource } from './SessionResource';
+
+export const SESSION_TOUCH_TIME_PERIOD = 1000 * 60;
+
+@injectable()
+export class SessionActivityService extends Dependency {
+ private touchSessionTimer: ReturnType | null = null;
+
+ constructor(private readonly clientActivityService: ClientActivityService, private readonly sessionResource: SessionResource) {
+ super();
+ this.notifyClientActivity = this.notifyClientActivity.bind(this);
+ this.clientActivityService.onActiveStateChange.addHandler(this.notifyClientActivity);
+ }
+
+ private async notifyClientActivity() {
+ if (this.touchSessionTimer || !this.clientActivityService.isActive) {
+ return;
+ }
+
+ try {
+ await this.sessionResource.updateSession();
+ } catch (e) {
+ console.error('Session update error', e);
+ }
+
+ this.touchSessionTimer = setTimeout(() => {
+ if (this.touchSessionTimer) {
+ clearTimeout(this.touchSessionTimer);
+ this.touchSessionTimer = null;
+ }
+ }, SESSION_TOUCH_TIME_PERIOD);
+ }
+}
diff --git a/webapp/packages/core-root/src/SessionExpireService.ts b/webapp/packages/core-root/src/SessionExpireService.ts
index 35ff9cbba9..af8acf44c4 100644
--- a/webapp/packages/core-root/src/SessionExpireService.ts
+++ b/webapp/packages/core-root/src/SessionExpireService.ts
@@ -9,16 +9,26 @@ import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { Executor, IExecutor } from '@cloudbeaver/core-executor';
import { EServerErrorCode, GQLError, GraphQLService, SessionError } from '@cloudbeaver/core-sdk';
import { errorOf } from '@cloudbeaver/core-utils';
+
+export const SESSION_EXPIRE_MIN_TIME = 5 * 1000 * 60;
+
@injectable()
export class SessionExpireService extends Bootstrap {
- expired = false;
+ private isExpired = false;
onSessionExpire: IExecutor;
constructor(private readonly graphQLService: GraphQLService) {
super();
+
+ this.sessionExpired = this.sessionExpired.bind(this);
+
this.onSessionExpire = new Executor();
}
+ get expired() {
+ return this.isExpired;
+ }
+
register(): void {
this.graphQLService.registerInterceptor(this.sessionExpiredInterceptor.bind(this));
}
@@ -32,7 +42,7 @@ export class SessionExpireService extends Bootstrap {
const e = new SessionError('Session expired');
this.graphQLService.blockRequests(e);
- this.expired = true;
+ this.isExpired = true;
this.onSessionExpire.execute();
}
diff --git a/webapp/packages/core-root/src/SessionResource.ts b/webapp/packages/core-root/src/SessionResource.ts
index 128ab591d1..b9479333a5 100644
--- a/webapp/packages/core-root/src/SessionResource.ts
+++ b/webapp/packages/core-root/src/SessionResource.ts
@@ -42,6 +42,11 @@ export class SessionResource extends CachedDataResource {
sessionInfoEventHandler.onEvent(
ServerEventId.CbSessionState,
event => {
+ if (this.data) {
+ this.data.valid = event.isValid ?? this.data.valid;
+ this.data.remainingTime = event.remainingTime;
+ // TODO: probably we want to call here this.dataUpdate
+ }
this.onStatusUpdate.execute(event);
},
undefined,
@@ -68,13 +73,6 @@ export class SessionResource extends CachedDataResource {
this.defaultLocale = defaultLocale;
}
- //! this method results in onDataUpdate handler skipping
- async refreshSilent(): Promise {
- const session = await this.loader();
-
- this.setData(session);
- }
-
async changeLanguage(locale: string): Promise {
if (this.data?.locale === locale) {
return;
@@ -95,6 +93,18 @@ export class SessionResource extends CachedDataResource {
return session;
}
+ async updateSession() {
+ if (!this.data?.valid) {
+ return;
+ }
+
+ const { updateSession } = await this.graphQLService.sdk.updateSession();
+
+ this.setData(updateSession);
+
+ return updateSession;
+ }
+
protected setData(data: SessionState | null) {
if (!this.action) {
this.action = data?.actionParameters;
diff --git a/webapp/packages/core-root/src/index.ts b/webapp/packages/core-root/src/index.ts
index 73db8658cd..8021c7a595 100644
--- a/webapp/packages/core-root/src/index.ts
+++ b/webapp/packages/core-root/src/index.ts
@@ -22,6 +22,7 @@ export * from './SessionDataResource';
export * from './SessionSettingsService';
export * from './SessionExpireService';
export * from './SessionExpireEventService';
+export * from './SessionActivityService';
export * from './ServerNodeService';
export * from './WindowEventsService';
export * from './manifest';
diff --git a/webapp/packages/core-root/src/manifest.ts b/webapp/packages/core-root/src/manifest.ts
index fcca411e18..5bfb8c7871 100644
--- a/webapp/packages/core-root/src/manifest.ts
+++ b/webapp/packages/core-root/src/manifest.ts
@@ -18,6 +18,7 @@ import { ServerNodeService } from './ServerNodeService';
import { ServerSettingsResolverService } from './ServerSettingsResolverService';
import { ServerSettingsService } from './ServerSettingsService';
import { SessionActionService } from './SessionActionService';
+import { SessionActivityService } from './SessionActivityService';
import { SessionDataResource } from './SessionDataResource';
import { SessionEventSource } from './SessionEventSource';
import { SessionExpireEventService } from './SessionExpireEventService';
@@ -53,6 +54,7 @@ export const coreRootManifest: PluginManifest = {
ServerConfigEventHandler,
SessionEventSource,
SessionInfoEventHandler,
+ SessionActivityService,
DataSynchronizationService,
SessionPermissionEventHandler,
ServerSettingsResolverService,
diff --git a/webapp/packages/core-root/tsconfig.json b/webapp/packages/core-root/tsconfig.json
index aa6e304abb..e13ad37489 100644
--- a/webapp/packages/core-root/tsconfig.json
+++ b/webapp/packages/core-root/tsconfig.json
@@ -11,6 +11,9 @@
"tsBuildInfoFile": "dist/tsconfig.tsbuildinfo"
},
"references": [
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/core-sdk/src/queries/session/updateSession.gql b/webapp/packages/core-sdk/src/queries/session/updateSession.gql
new file mode 100644
index 0000000000..7f2e18ae49
--- /dev/null
+++ b/webapp/packages/core-sdk/src/queries/session/updateSession.gql
@@ -0,0 +1,5 @@
+mutation updateSession {
+ updateSession {
+ ...SessionState
+ }
+}
diff --git a/webapp/packages/core-settings-localization/package.json b/webapp/packages/core-settings-localization/package.json
index 2b8bd9af21..b35223ce4c 100644
--- a/webapp/packages/core-settings-localization/package.json
+++ b/webapp/packages/core-settings-localization/package.json
@@ -28,6 +28,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
"@cloudbeaver/core-product": "~0.1.0",
diff --git a/webapp/packages/core-settings-localization/src/SettingsLocalizationService.test.ts b/webapp/packages/core-settings-localization/src/SettingsLocalizationService.test.ts
index 137f52adfb..2f21b81772 100644
--- a/webapp/packages/core-settings-localization/src/SettingsLocalizationService.test.ts
+++ b/webapp/packages/core-settings-localization/src/SettingsLocalizationService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
import { coreProductManifest } from '@cloudbeaver/core-product';
@@ -33,6 +34,7 @@ const app = createApp(
coreRootManifest,
coreSDKManifest,
coreBrowserManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/core-settings-localization/tsconfig.json b/webapp/packages/core-settings-localization/tsconfig.json
index 07cec65421..2cce098093 100644
--- a/webapp/packages/core-settings-localization/tsconfig.json
+++ b/webapp/packages/core-settings-localization/tsconfig.json
@@ -9,6 +9,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/core-theming/package.json b/webapp/packages/core-theming/package.json
index 38b524a3ad..6050b1931b 100644
--- a/webapp/packages/core-theming/package.json
+++ b/webapp/packages/core-theming/package.json
@@ -31,6 +31,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/core-theming/src/ThemeSettingsService.test.ts b/webapp/packages/core-theming/src/ThemeSettingsService.test.ts
index 8a44f7f6aa..83eeda9986 100644
--- a/webapp/packages/core-theming/src/ThemeSettingsService.test.ts
+++ b/webapp/packages/core-theming/src/ThemeSettingsService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -35,6 +36,7 @@ const app = createApp(
coreSettingsManifest,
coreBrowserManifest,
coreLocalizationManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/core-theming/tsconfig.json b/webapp/packages/core-theming/tsconfig.json
index 27d72bccb4..0f4fc71597 100644
--- a/webapp/packages/core-theming/tsconfig.json
+++ b/webapp/packages/core-theming/tsconfig.json
@@ -9,6 +9,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm.tsx b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm.tsx
index 0e85707f45..df5410df09 100644
--- a/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm.tsx
+++ b/webapp/packages/plugin-administration/src/ConfigurationWizard/ServerConfiguration/Form/ServerConfigurationInfoForm.tsx
@@ -8,7 +8,7 @@
import { observer } from 'mobx-react-lite';
import { Group, GroupTitle, InputField, useResource, useTranslate } from '@cloudbeaver/core-blocks';
-import { ServerConfigResource } from '@cloudbeaver/core-root';
+import { ServerConfigResource, SESSION_EXPIRE_MIN_TIME, SESSION_TOUCH_TIME_PERIOD } from '@cloudbeaver/core-root';
import type { IServerConfigurationPageState } from '../IServerConfigurationPageState';
@@ -16,6 +16,8 @@ interface Props {
state: IServerConfigurationPageState;
}
+const INPUT_MIN_SESSION_EXPIRE_TIME = Math.ceil((SESSION_EXPIRE_MIN_TIME + SESSION_TOUCH_TIME_PERIOD) / 60000) + 1;
+
export const ServerConfigurationInfoForm = observer(function ServerConfigurationInfoForm({ state }) {
const serverConfigLoader = useResource(ServerConfigurationInfoForm, ServerConfigResource, undefined);
const translate = useTranslate();
@@ -41,7 +43,7 @@ export const ServerConfigurationInfoForm = observer(function ServerConfig
type="number"
name="sessionExpireTime"
state={state.serverConfig}
- min={1}
+ min={INPUT_MIN_SESSION_EXPIRE_TIME}
mapState={(v: number | undefined) => String((v === 0 ? 60000 : v ?? 1800000) / 1000 / 60)}
mapValue={(v?: string) => (v === undefined ? 30 : Number(v) || 1) * 1000 * 60}
required
diff --git a/webapp/packages/plugin-data-export/package.json b/webapp/packages/plugin-data-export/package.json
index 14308b2ca4..cca56232f5 100644
--- a/webapp/packages/plugin-data-export/package.json
+++ b/webapp/packages/plugin-data-export/package.json
@@ -45,6 +45,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-connections": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
diff --git a/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts b/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts
index 857d4e7ef9..a312548387 100644
--- a/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts
+++ b/webapp/packages/plugin-data-export/src/DataExportSettingsService.test.ts
@@ -12,6 +12,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreConnectionsManifest } from '@cloudbeaver/core-connections';
import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
import { coreEventsManifest } from '@cloudbeaver/core-events';
@@ -68,6 +69,7 @@ const app = createApp(
navigationTabsPlugin,
objectViewerManifest,
dataViewerManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/plugin-data-export/tsconfig.json b/webapp/packages/plugin-data-export/tsconfig.json
index bd41a73288..9c21a8add0 100644
--- a/webapp/packages/plugin-data-export/tsconfig.json
+++ b/webapp/packages/plugin-data-export/tsconfig.json
@@ -21,6 +21,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-connections/tsconfig.json"
},
diff --git a/webapp/packages/plugin-data-spreadsheet-new/package.json b/webapp/packages/plugin-data-spreadsheet-new/package.json
index 8d81074eb7..35d922a02e 100644
--- a/webapp/packages/plugin-data-spreadsheet-new/package.json
+++ b/webapp/packages/plugin-data-spreadsheet-new/package.json
@@ -48,6 +48,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-connections": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
diff --git a/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts b/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts
index 6b0b4c495f..99ffe65f11 100644
--- a/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts
+++ b/webapp/packages/plugin-data-spreadsheet-new/src/DataGridSettingsService.test.ts
@@ -12,6 +12,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreConnectionsManifest } from '@cloudbeaver/core-connections';
import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
import { coreEventsManifest } from '@cloudbeaver/core-events';
@@ -68,6 +69,7 @@ const app = createApp(
navigationTabsPlugin,
objectViewerManifest,
dataViewerManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json b/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json
index cdce42e1b9..5a51933c77 100644
--- a/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json
+++ b/webapp/packages/plugin-data-spreadsheet-new/tsconfig.json
@@ -24,6 +24,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-connections/tsconfig.json"
},
diff --git a/webapp/packages/plugin-data-viewer/package.json b/webapp/packages/plugin-data-viewer/package.json
index a2ceda3a6c..ee5db29317 100644
--- a/webapp/packages/plugin-data-viewer/package.json
+++ b/webapp/packages/plugin-data-viewer/package.json
@@ -50,6 +50,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-connections": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerService.ts b/webapp/packages/plugin-data-viewer/src/DataViewerService.ts
index 27b95e75c3..c72a5278c4 100644
--- a/webapp/packages/plugin-data-viewer/src/DataViewerService.ts
+++ b/webapp/packages/plugin-data-viewer/src/DataViewerService.ts
@@ -7,19 +7,33 @@
*/
import type { Connection } from '@cloudbeaver/core-connections';
import { injectable } from '@cloudbeaver/core-di';
+import { EAdminPermission, SessionPermissionsResource } from '@cloudbeaver/core-root';
import { DataViewerSettingsService } from './DataViewerSettingsService';
@injectable()
export class DataViewerService {
get canCopyData() {
+ if (this.sessionPermissionsResource.has(EAdminPermission.admin)) {
+ return true;
+ }
+
return !this.dataViewerSettingsService.settings.getValue('disableCopyData');
}
- constructor(private readonly dataViewerSettingsService: DataViewerSettingsService) {}
+ constructor(
+ private readonly dataViewerSettingsService: DataViewerSettingsService,
+ private readonly sessionPermissionsResource: SessionPermissionsResource,
+ ) {}
isDataEditable(connection: Connection) {
+ if (connection.readOnly) {
+ return false;
+ }
+
+ const isAdmin = this.sessionPermissionsResource.has(EAdminPermission.admin);
const disabled = this.dataViewerSettingsService.settings.getValue('disableEdit');
- return !disabled && !connection.readOnly;
+
+ return isAdmin || !disabled;
}
}
diff --git a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts
index b496ab7f2d..522eac178f 100644
--- a/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts
+++ b/webapp/packages/plugin-data-viewer/src/DataViewerSettingsService.test.ts
@@ -12,6 +12,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreConnectionsManifest } from '@cloudbeaver/core-connections';
import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
import { coreEventsManifest } from '@cloudbeaver/core-events';
@@ -66,6 +67,7 @@ const app = createApp(
navigationTreePlugin,
navigationTabsPlugin,
objectViewerManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/plugin-data-viewer/src/locales/en.ts b/webapp/packages/plugin-data-viewer/src/locales/en.ts
index 6831fdab89..afeb6a8def 100644
--- a/webapp/packages/plugin-data-viewer/src/locales/en.ts
+++ b/webapp/packages/plugin-data-viewer/src/locales/en.ts
@@ -50,9 +50,9 @@ export default [
['data_viewer_model_not_loaded', 'Table model is not loaded'],
['settings_data_editor', 'Data Editor'],
['settings_data_editor_disable_edit_name', 'Disable Edit'],
- ['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer'],
+ ['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer for non-admin users'],
['settings_data_editor_disable_data_copy_name', 'Disable Copy'],
- ['settings_data_editor_disable_data_copy_description', 'Disable copying of data in Data Viewer'],
+ ['settings_data_editor_disable_data_copy_description', 'Disable copying of data in Data Viewer for non-admin users'],
['settings_data_editor_fetch_min_name', 'Minimum fetch size'],
['settings_data_editor_fetch_min_description', 'Minimum number of rows to fetch'],
['settings_data_editor_fetch_max_name', 'Maximum fetch size'],
diff --git a/webapp/packages/plugin-data-viewer/src/locales/it.ts b/webapp/packages/plugin-data-viewer/src/locales/it.ts
index 35306f85a3..a35769e675 100644
--- a/webapp/packages/plugin-data-viewer/src/locales/it.ts
+++ b/webapp/packages/plugin-data-viewer/src/locales/it.ts
@@ -43,9 +43,9 @@ export default [
['data_viewer_model_not_loaded', 'Table model is not loaded'],
['settings_data_editor', 'Data Editor'],
['settings_data_editor_disable_edit_name', 'Disable Edit'],
- ['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer'],
+ ['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer for non-admin users'],
['settings_data_editor_disable_data_copy_name', 'Disable Copy'],
- ['settings_data_editor_disable_data_copy_description', 'Disable copying of data in Data Viewer'],
+ ['settings_data_editor_disable_data_copy_description', 'Disable copying of data in Data Viewer for non-admin users'],
['settings_data_editor_fetch_min_name', 'Minimum fetch size'],
['settings_data_editor_fetch_min_description', 'Minimum number of rows to fetch'],
['settings_data_editor_fetch_max_name', 'Maximum fetch size'],
diff --git a/webapp/packages/plugin-data-viewer/src/locales/ru.ts b/webapp/packages/plugin-data-viewer/src/locales/ru.ts
index 05dd579c74..307b45cd6b 100644
--- a/webapp/packages/plugin-data-viewer/src/locales/ru.ts
+++ b/webapp/packages/plugin-data-viewer/src/locales/ru.ts
@@ -44,9 +44,9 @@ export default [
['data_viewer_model_not_loaded', 'Не удалось загрузить модель таблицы'],
['settings_data_editor', 'Редактор данных'],
['settings_data_editor_disable_edit_name', 'Отключить редактирование'],
- ['settings_data_editor_disable_edit_description', 'Отключить редактирование данных'],
+ ['settings_data_editor_disable_edit_description', 'Отключить редактирование данных для пользователей без прав администратора'],
['settings_data_editor_disable_data_copy_name', 'Отключить копирование'],
- ['settings_data_editor_disable_data_copy_description', 'Отключить копирование данных'],
+ ['settings_data_editor_disable_data_copy_description', 'Отключить копирование данных для пользователей без прав администратора'],
['settings_data_editor_fetch_min_name', 'Минимальный размер выборки'],
['settings_data_editor_fetch_min_description', 'Минимальное количество строк для выборки'],
['settings_data_editor_fetch_max_name', 'Максимальный размер выборки'],
diff --git a/webapp/packages/plugin-data-viewer/src/locales/zh.ts b/webapp/packages/plugin-data-viewer/src/locales/zh.ts
index 4c0bba6c65..d5bf26d577 100644
--- a/webapp/packages/plugin-data-viewer/src/locales/zh.ts
+++ b/webapp/packages/plugin-data-viewer/src/locales/zh.ts
@@ -50,9 +50,9 @@ export default [
['data_viewer_model_not_loaded', 'Table model is not loaded'],
['settings_data_editor', 'Data Editor'],
['settings_data_editor_disable_edit_name', 'Disable Edit'],
- ['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer'],
+ ['settings_data_editor_disable_edit_description', 'Disable editing of data in Data Viewer for non-admin users'],
['settings_data_editor_disable_data_copy_name', 'Disable Copy'],
- ['settings_data_editor_disable_data_copy_description', 'Disable copying of data in Data Viewer'],
+ ['settings_data_editor_disable_data_copy_description', 'Disable copying of data in Data Viewer for non-admin users'],
['settings_data_editor_fetch_min_name', 'Minimum fetch size'],
['settings_data_editor_fetch_min_description', 'Minimum number of rows to fetch'],
['settings_data_editor_fetch_max_name', 'Maximum fetch size'],
diff --git a/webapp/packages/plugin-data-viewer/tsconfig.json b/webapp/packages/plugin-data-viewer/tsconfig.json
index 83e81ca240..af109b34e3 100644
--- a/webapp/packages/plugin-data-viewer/tsconfig.json
+++ b/webapp/packages/plugin-data-viewer/tsconfig.json
@@ -24,6 +24,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-connections/tsconfig.json"
},
diff --git a/webapp/packages/plugin-log-viewer/package.json b/webapp/packages/plugin-log-viewer/package.json
index 56ad8ff9e9..5ac07403b3 100644
--- a/webapp/packages/plugin-log-viewer/package.json
+++ b/webapp/packages/plugin-log-viewer/package.json
@@ -39,6 +39,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerSettingsService.test.ts b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerSettingsService.test.ts
index 1c70c2b82f..3ae780ca4e 100644
--- a/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerSettingsService.test.ts
+++ b/webapp/packages/plugin-log-viewer/src/LogViewer/LogViewerSettingsService.test.ts
@@ -11,6 +11,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -48,6 +49,7 @@ const app = createApp(
coreAppManifest,
coreRoutingManifest,
coreThemingManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/plugin-log-viewer/tsconfig.json b/webapp/packages/plugin-log-viewer/tsconfig.json
index ba06aa67a9..8849b8f400 100644
--- a/webapp/packages/plugin-log-viewer/tsconfig.json
+++ b/webapp/packages/plugin-log-viewer/tsconfig.json
@@ -21,6 +21,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/plugin-navigation-tree/package.json b/webapp/packages/plugin-navigation-tree/package.json
index 9a43574cb0..249e835536 100644
--- a/webapp/packages/plugin-navigation-tree/package.json
+++ b/webapp/packages/plugin-navigation-tree/package.json
@@ -47,6 +47,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-connections": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
diff --git a/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeView/NavNodeViewService.test.ts b/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeView/NavNodeViewService.test.ts
index 4fdf772116..23980e341c 100644
--- a/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeView/NavNodeViewService.test.ts
+++ b/webapp/packages/plugin-navigation-tree/src/NodesManager/NavNodeView/NavNodeViewService.test.ts
@@ -12,6 +12,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreConnectionsManifest } from '@cloudbeaver/core-connections';
import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
import { coreEventsManifest } from '@cloudbeaver/core-events';
@@ -61,6 +62,7 @@ const app = createApp(
coreNavigationTree,
coreAppManifest,
coreThemingManifest,
+ coreClientActivityManifest,
);
mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/plugin-navigation-tree/tsconfig.json b/webapp/packages/plugin-navigation-tree/tsconfig.json
index 44067ff3ca..6edb4662a5 100644
--- a/webapp/packages/plugin-navigation-tree/tsconfig.json
+++ b/webapp/packages/plugin-navigation-tree/tsconfig.json
@@ -24,6 +24,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-connections/tsconfig.json"
},
diff --git a/webapp/packages/plugin-resource-manager/package.json b/webapp/packages/plugin-resource-manager/package.json
index 6454b5bd6f..39633b3548 100644
--- a/webapp/packages/plugin-resource-manager/package.json
+++ b/webapp/packages/plugin-resource-manager/package.json
@@ -33,6 +33,7 @@
"peerDependencies": {},
"devDependencies": {
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
"@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-plugin": "~0.1.0",
diff --git a/webapp/packages/plugin-resource-manager/src/ResourceManagerSettingsService.test.ts b/webapp/packages/plugin-resource-manager/src/ResourceManagerSettingsService.test.ts
index f72f4ffca2..c63be311bb 100644
--- a/webapp/packages/plugin-resource-manager/src/ResourceManagerSettingsService.test.ts
+++ b/webapp/packages/plugin-resource-manager/src/ResourceManagerSettingsService.test.ts
@@ -8,6 +8,7 @@
import '@testing-library/jest-dom';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreEventsManifest } from '@cloudbeaver/core-events';
import { coreLocalizationManifest } from '@cloudbeaver/core-localization';
import { corePluginManifest } from '@cloudbeaver/core-plugin';
@@ -35,6 +36,7 @@ const app = createApp(
coreSettingsManifest,
coreBrowserManifest,
coreLocalizationManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint));
diff --git a/webapp/packages/plugin-resource-manager/tsconfig.json b/webapp/packages/plugin-resource-manager/tsconfig.json
index bd08ea8c68..98ccf5e9f7 100644
--- a/webapp/packages/plugin-resource-manager/tsconfig.json
+++ b/webapp/packages/plugin-resource-manager/tsconfig.json
@@ -12,6 +12,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-di/tsconfig.json"
},
diff --git a/webapp/packages/plugin-session-expiration/package.json b/webapp/packages/plugin-session-expiration/package.json
index 11c81689ad..ad3de79c63 100644
--- a/webapp/packages/plugin-session-expiration/package.json
+++ b/webapp/packages/plugin-session-expiration/package.json
@@ -22,6 +22,7 @@
"@cloudbeaver/core-di": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
+ "@cloudbeaver/core-localization": "~0.1.0",
"@cloudbeaver/core-root": "~0.1.0",
"@cloudbeaver/core-routing": "~0.1.0",
"@cloudbeaver/core-sdk": "~0.1.0",
diff --git a/webapp/packages/plugin-session-expiration/src/LocaleService.ts b/webapp/packages/plugin-session-expiration/src/LocaleService.ts
new file mode 100644
index 0000000000..edeb82d255
--- /dev/null
+++ b/webapp/packages/plugin-session-expiration/src/LocaleService.ts
@@ -0,0 +1,35 @@
+/*
+ * CloudBeaver - Cloud Database Manager
+ * Copyright (C) 2020-2024 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 { Bootstrap, injectable } from '@cloudbeaver/core-di';
+import { LocalizationService } from '@cloudbeaver/core-localization';
+
+@injectable()
+export class LocaleService extends Bootstrap {
+ constructor(private readonly localizationService: LocalizationService) {
+ super();
+ }
+
+ register(): void | Promise {
+ this.localizationService.addProvider(this.provider.bind(this));
+ }
+
+ load(): void | Promise {}
+
+ private async provider(locale: string) {
+ switch (locale) {
+ case 'ru':
+ return (await import('./locales/ru')).default;
+ case 'it':
+ return (await import('./locales/it')).default;
+ case 'zh':
+ return (await import('./locales/zh')).default;
+ default:
+ return (await import('./locales/en')).default;
+ }
+ }
+}
diff --git a/webapp/packages/plugin-session-expiration/src/SessionExpireWarningDialog/SessionExpireWarningDialogBootstrap.ts b/webapp/packages/plugin-session-expiration/src/SessionExpireWarningDialog/SessionExpireWarningDialogBootstrap.ts
index 7db83e316b..7567820fb4 100644
--- a/webapp/packages/plugin-session-expiration/src/SessionExpireWarningDialog/SessionExpireWarningDialogBootstrap.ts
+++ b/webapp/packages/plugin-session-expiration/src/SessionExpireWarningDialog/SessionExpireWarningDialogBootstrap.ts
@@ -6,15 +6,14 @@
* you may not use this file except in compliance with the License.
*/
import { UserInfoResource } from '@cloudbeaver/core-authentication';
+import { importLazyComponent } from '@cloudbeaver/core-blocks';
import { Bootstrap, injectable } from '@cloudbeaver/core-di';
import { CommonDialogService, DialogueStateResult } from '@cloudbeaver/core-dialogs';
-import { ServerConfigResource, SessionExpireService, SessionResource } from '@cloudbeaver/core-root';
+import { NotificationService } from '@cloudbeaver/core-events';
+import { ServerConfigResource, SESSION_EXPIRE_MIN_TIME, SessionExpireService, SessionResource } from '@cloudbeaver/core-root';
import { GraphQLService } from '@cloudbeaver/core-sdk';
-import { SessionExpireWarningDialog } from './SessionExpireWarningDialog';
-
-const WARN_IN = 5 * 1000 * 60;
-
+const SessionExpireWarningDialog = importLazyComponent(() => import('./SessionExpireWarningDialog').then(m => m.SessionExpireWarningDialog));
@injectable()
export class SessionExpireWarningDialogBootstrap extends Bootstrap {
private dialogInternalPromise: Promise | null;
@@ -25,6 +24,7 @@ export class SessionExpireWarningDialogBootstrap extends Bootstrap {
private readonly sessionResource: SessionResource,
private readonly userInfoResource: UserInfoResource,
private readonly graphQLService: GraphQLService,
+ private readonly notificationService: NotificationService,
) {
super();
this.dialogInternalPromise = null;
@@ -52,12 +52,12 @@ export class SessionExpireWarningDialogBootstrap extends Bootstrap {
const sessionDuration = this.serverConfigResource.data?.sessionExpireTime;
- if (this.sessionExpireService.expired || !sessionDuration || sessionDuration < WARN_IN) {
+ if (this.sessionExpireService.expired || !sessionDuration || sessionDuration < SESSION_EXPIRE_MIN_TIME) {
this.close();
return;
}
- if (remainingTime !== undefined && remainingTime < WARN_IN) {
+ if (remainingTime !== undefined && remainingTime <= SESSION_EXPIRE_MIN_TIME) {
this.open();
} else {
this.close();
@@ -74,7 +74,11 @@ export class SessionExpireWarningDialogBootstrap extends Bootstrap {
const { sessionState } = await this.graphQLService.sdk.sessionState();
if (sessionState.valid) {
- await this.sessionResource.refreshSilent();
+ try {
+ await this.sessionResource.updateSession();
+ } catch (e: any) {
+ this.notificationService.logException(e, 'plugin_session_expiration_session_update_error');
+ }
} else {
this.sessionExpireService.sessionExpired();
}
diff --git a/webapp/packages/plugin-session-expiration/src/locales/en.ts b/webapp/packages/plugin-session-expiration/src/locales/en.ts
new file mode 100644
index 0000000000..8c94cf3aff
--- /dev/null
+++ b/webapp/packages/plugin-session-expiration/src/locales/en.ts
@@ -0,0 +1 @@
+export default [['plugin_session_expiration_session_update_error', 'Session update failed']];
diff --git a/webapp/packages/plugin-session-expiration/src/locales/it.ts b/webapp/packages/plugin-session-expiration/src/locales/it.ts
new file mode 100644
index 0000000000..8c94cf3aff
--- /dev/null
+++ b/webapp/packages/plugin-session-expiration/src/locales/it.ts
@@ -0,0 +1 @@
+export default [['plugin_session_expiration_session_update_error', 'Session update failed']];
diff --git a/webapp/packages/plugin-session-expiration/src/locales/ru.ts b/webapp/packages/plugin-session-expiration/src/locales/ru.ts
new file mode 100644
index 0000000000..4404022cc8
--- /dev/null
+++ b/webapp/packages/plugin-session-expiration/src/locales/ru.ts
@@ -0,0 +1 @@
+export default [['plugin_session_expiration_session_update_error', 'Не удалось обновить сессию']];
diff --git a/webapp/packages/plugin-session-expiration/src/locales/zh.ts b/webapp/packages/plugin-session-expiration/src/locales/zh.ts
new file mode 100644
index 0000000000..8c94cf3aff
--- /dev/null
+++ b/webapp/packages/plugin-session-expiration/src/locales/zh.ts
@@ -0,0 +1 @@
+export default [['plugin_session_expiration_session_update_error', 'Session update failed']];
diff --git a/webapp/packages/plugin-session-expiration/src/manifest.ts b/webapp/packages/plugin-session-expiration/src/manifest.ts
index ec5034d135..e625ebfafd 100644
--- a/webapp/packages/plugin-session-expiration/src/manifest.ts
+++ b/webapp/packages/plugin-session-expiration/src/manifest.ts
@@ -7,11 +7,12 @@
*/
import type { PluginManifest } from '@cloudbeaver/core-di';
+import { LocaleService } from './LocaleService';
import { PluginBootstrap } from './PluginBootstrap';
import { SessionExpiredDialogBootstrap } from './SessionExpireDialog/SessionExpiredDialogBootstrap';
import { SessionExpireWarningDialogBootstrap } from './SessionExpireWarningDialog/SessionExpireWarningDialogBootstrap';
export const sessionExpirationPlugin: PluginManifest = {
info: { name: 'Session Expiration plugin' },
- providers: [PluginBootstrap, SessionExpiredDialogBootstrap, SessionExpireWarningDialogBootstrap],
+ providers: [PluginBootstrap, SessionExpiredDialogBootstrap, SessionExpireWarningDialogBootstrap, LocaleService],
};
diff --git a/webapp/packages/plugin-session-expiration/tsconfig.json b/webapp/packages/plugin-session-expiration/tsconfig.json
index 9c615c7d0b..471e24ac2c 100644
--- a/webapp/packages/plugin-session-expiration/tsconfig.json
+++ b/webapp/packages/plugin-session-expiration/tsconfig.json
@@ -21,6 +21,9 @@
{
"path": "../core-events/tsconfig.json"
},
+ {
+ "path": "../core-localization/tsconfig.json"
+ },
{
"path": "../core-root/tsconfig.json"
},
diff --git a/webapp/packages/plugin-sql-editor/package.json b/webapp/packages/plugin-sql-editor/package.json
index b04c08836c..5adaad5da1 100644
--- a/webapp/packages/plugin-sql-editor/package.json
+++ b/webapp/packages/plugin-sql-editor/package.json
@@ -51,6 +51,7 @@
"@cloudbeaver/core-app": "~0.1.0",
"@cloudbeaver/core-authentication": "~0.1.0",
"@cloudbeaver/core-browser": "~0.1.0",
+ "@cloudbeaver/core-client-activity": "~0.1.0",
"@cloudbeaver/core-connections": "~0.1.0",
"@cloudbeaver/core-dialogs": "~0.1.0",
"@cloudbeaver/core-events": "~0.1.0",
diff --git a/webapp/packages/plugin-sql-editor/src/SqlEditorSettingsService.test.ts b/webapp/packages/plugin-sql-editor/src/SqlEditorSettingsService.test.ts
index e6e69b43f9..8730ae712e 100644
--- a/webapp/packages/plugin-sql-editor/src/SqlEditorSettingsService.test.ts
+++ b/webapp/packages/plugin-sql-editor/src/SqlEditorSettingsService.test.ts
@@ -12,6 +12,7 @@ import { coreAppManifest } from '@cloudbeaver/core-app';
import { coreAuthenticationManifest } from '@cloudbeaver/core-authentication';
import { mockAuthentication } from '@cloudbeaver/core-authentication/dist/__custom_mocks__/mockAuthentication';
import { coreBrowserManifest } from '@cloudbeaver/core-browser';
+import { coreClientActivityManifest } from '@cloudbeaver/core-client-activity';
import { coreConnectionsManifest } from '@cloudbeaver/core-connections';
import { coreDialogsManifest } from '@cloudbeaver/core-dialogs';
import { coreEventsManifest } from '@cloudbeaver/core-events';
@@ -68,6 +69,7 @@ const app = createApp(
navigationTabsPlugin,
objectViewerManifest,
dataViewerManifest,
+ coreClientActivityManifest,
);
const server = mockGraphQL(...mockAppInit(endpoint), ...mockAuthentication(endpoint));
diff --git a/webapp/packages/plugin-sql-editor/tsconfig.json b/webapp/packages/plugin-sql-editor/tsconfig.json
index a2fa50c048..9b032c32e6 100644
--- a/webapp/packages/plugin-sql-editor/tsconfig.json
+++ b/webapp/packages/plugin-sql-editor/tsconfig.json
@@ -24,6 +24,9 @@
{
"path": "../core-browser/tsconfig.json"
},
+ {
+ "path": "../core-client-activity/tsconfig.json"
+ },
{
"path": "../core-connections/tsconfig.json"
},