diff --git a/.github/workflows/ci-js.yml b/.github/workflows/ci-js.yml
index 43145c6444..c7aa349d36 100644
--- a/.github/workflows/ci-js.yml
+++ b/.github/workflows/ci-js.yml
@@ -4,9 +4,11 @@ on:
push:
branches:
- main
+ - opensight-ui
pull_request:
branches:
- main
+ - opensight-ui
jobs:
testing:
diff --git a/package-lock.json b/package-lock.json
index 333eeb28bc..ae3a44c5fb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,7 +9,7 @@
"version": "23.0.1-dev1",
"license": "AGPL-3.0+",
"dependencies": {
- "@greenbone/opensight-ui-components": "^0.1.3-alpha1",
+ "@greenbone/opensight-ui-components": "^0.3.0",
"@mantine/core": "^6.0.0",
"@reduxjs/toolkit": "^2.2.5",
"@sentry/react": "^8.7.0",
@@ -2835,20 +2835,20 @@
"integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q=="
},
"node_modules/@greenbone/opensight-ui-components": {
- "version": "0.1.3-alpha2",
- "resolved": "https://registry.npmjs.org/@greenbone/opensight-ui-components/-/opensight-ui-components-0.1.3-alpha2.tgz",
- "integrity": "sha512-Kn16uRoKO7pruC10FUR+Qoyw1aXmXCNZOkx+j+nE1+Y8E2YhvT0xJu9clg1mQYQHVaUXJ1DM4XOo5azWRL08vw==",
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@greenbone/opensight-ui-components/-/opensight-ui-components-0.3.0.tgz",
+ "integrity": "sha512-Nf90SoaYP74I2fRA/cyx06xbdjBho7zuKP4hQkkZUJKx3uIH4QhH0NbltOvHt8a60xRgCIjVanPpDDUwhwP3MA==",
"dependencies": {
"@mantine/core": "^6.x.x",
"@mantine/dates": "^6.x.x",
"@mantine/hooks": "^6.x.x",
"@mantine/notifications": "^6.x.x",
- "lucide-react": "^0.376.0",
+ "lucide-react": "^0.390.0",
"luxon": "^3.4.4",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hook-form": "^7",
- "react-i18next": "^14.1.1",
+ "react-i18next": "^14.1.2",
"react-select": "^5.8.0",
"tiny-invariant": "^1.3.3",
"urlcat": "^3",
@@ -2856,7 +2856,7 @@
"yup": "^1.4.0"
},
"optionalDependencies": {
- "@reduxjs/toolkit": "^2.2.3",
+ "@reduxjs/toolkit": "^2.2.5",
"@swc/core-darwin-arm64": "^1.3.107"
},
"peerDependencies": {
@@ -2871,9 +2871,9 @@
}
},
"node_modules/@greenbone/opensight-ui-components/node_modules/lucide-react": {
- "version": "0.376.0",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.376.0.tgz",
- "integrity": "sha512-g91IX3ERD6yUR1TL2dsL4BkcGygpZz/EsqjAeL/kcRQV0EApIOr/9eBfKhYOVyQIcGGuotFGjF3xKLHMEz+b7g==",
+ "version": "0.390.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.390.0.tgz",
+ "integrity": "sha512-APqbfEcVuHnZbiy3E97gYWLeBdkE4e6NbY6AuVETZDZVn/bQCHYUoHyxcUHyvRopfPOHhFUEvDyyQzHwM+S9/w==",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0"
}
diff --git a/package.json b/package.json
index 0b2816a161..bbe4739390 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,7 @@
"node": ">=18.0"
},
"dependencies": {
- "@greenbone/opensight-ui-components": "^0.1.3-alpha1",
+ "@greenbone/opensight-ui-components": "^0.3.0",
"@mantine/core": "^6.0.0",
"@reduxjs/toolkit": "^2.2.5",
"@sentry/react": "^8.7.0",
diff --git a/src/web/components/sessionTimer/SessionTimer.jsx b/src/web/components/sessionTimer/SessionTimer.jsx
new file mode 100644
index 0000000000..6af1f28fb0
--- /dev/null
+++ b/src/web/components/sessionTimer/SessionTimer.jsx
@@ -0,0 +1,54 @@
+import {useEffect, useState} from 'react';
+
+import useUserSessionTimeout from 'web/utils/useUserSessionTimeout';
+import date from 'gmp/models/date';
+import {RefreshCcw} from 'lucide-react';
+import Divider from 'web/components/layout/divider';
+import {ActionIcon} from '@mantine/core';
+import useTranslation from 'web/hooks/useTranslation';
+
+const SessionTimer = () => {
+ const [sessionTimeout, renewSession] = useUserSessionTimeout();
+ const [timeLeft, setTimeLeft] = useState('');
+ const [_] = useTranslation();
+
+ useEffect(() => {
+ const updateTimeLeft = () => {
+ if (!sessionTimeout) {
+ return
Session timer is currently unavailable.
;
+ }
+ const now = date();
+ const duration = date.duration(sessionTimeout.diff(now));
+ if (duration.asSeconds() <= 0) {
+ setTimeLeft('00:00');
+ } else {
+ const formatted =
+ Math.floor(duration.asMinutes()) +
+ ':' +
+ ('0' + duration.seconds()).slice(-2);
+ setTimeLeft(formatted);
+ }
+ };
+
+ updateTimeLeft();
+ const intervalId = setInterval(updateTimeLeft, 1000);
+
+ return () => clearInterval(intervalId);
+ }, [sessionTimeout]);
+
+ return (
+
+ {timeLeft}
+
+
+
+
+ );
+};
+
+export default SessionTimer;
diff --git a/src/web/components/structure/header.jsx b/src/web/components/structure/header.jsx
index 8f8de43026..c56f272874 100644
--- a/src/web/components/structure/header.jsx
+++ b/src/web/components/structure/header.jsx
@@ -15,7 +15,7 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
-import React, {useCallback} from 'react';
+import {useCallback} from 'react';
import {useHistory} from 'react-router-dom';
@@ -30,6 +30,7 @@ import useGmp from 'web/utils/useGmp';
import LogoutIcon from 'web/components/icon/logouticon';
import MySettingsIcon from 'web/components/icon/mysettingsicon';
import LanguageSwitch from './languageswitch';
+import SessionTimer from '../sessionTimer/SessionTimer';
const Header = () => {
const gmp = useGmp();
@@ -73,6 +74,7 @@ const Header = () => {
languageSwitch={}
menuPoints={menuPoints}
isLoggedIn={loggedIn}
+ sessionTimer={}
username={username}
logoLink="/"
/>
diff --git a/src/web/utils/__tests__/useUserSessionTimeout.jsx b/src/web/utils/__tests__/useUserSessionTimeout.jsx
index 9689be606f..34214a7fe9 100644
--- a/src/web/utils/__tests__/useUserSessionTimeout.jsx
+++ b/src/web/utils/__tests__/useUserSessionTimeout.jsx
@@ -22,16 +22,19 @@ import date from 'gmp/models/date';
import {setSessionTimeout as setSessionTimeoutAction} from 'web/store/usersettings/actions';
-import {rendererWith, fireEvent} from '../testing';
+import {rendererWith} from '../testing';
import useUserSessionTimeout from '../useUserSessionTimeout';
const TestUserSessionTimeout = () => {
const [sessionTimeout, setSessionTimeout] = useUserSessionTimeout();
return (
- setSessionTimeout(date('2020-03-10'))}>
+
+
);
};
@@ -47,20 +50,4 @@ describe('useUserSessionTimeout tests', () => {
expect(element).toHaveTextContent(/^10-10-19$/);
});
-
- test('should allow to set the users session timeout', () => {
- const {render, store} = rendererWith({store: true});
-
- const timeout = date('2019-10-10');
-
- store.dispatch(setSessionTimeoutAction(timeout));
-
- const {element} = render();
-
- expect(element).toHaveTextContent(/^10-10-19$/);
-
- fireEvent.click(element);
-
- expect(element).toHaveTextContent(/^10-03-20$/);
- });
});
diff --git a/src/web/utils/useUserSessionTimeout.jsx b/src/web/utils/useUserSessionTimeout.jsx
index 761600e4a1..317fe4c063 100644
--- a/src/web/utils/useUserSessionTimeout.jsx
+++ b/src/web/utils/useUserSessionTimeout.jsx
@@ -19,13 +19,29 @@ import {useSelector, useDispatch} from 'react-redux';
import {getSessionTimeout} from 'web/store/usersettings/selectors';
import {setSessionTimeout} from 'web/store/usersettings/actions';
+import useGmp from 'web/utils/useGmp';
+
+/**
+ * Custom hook to manage user session timeout.
+ *
+ * This hook provides the current session timeout, represented as a moment object, and a function to renew the session timeout through an API call.
+ * The `renewSessionAndUpdateTimeout` function makes an API call to renew the session and updates the session timeout based on the response, also represented as a moment object.
+ * This function does not require any parameters and will update the session timeout to the new value obtained from the API response.
+ *
+ * @returns {Array} An array containing the current `sessionTimeout` as a moment object and the `renewSessionAndUpdateTimeout` function.
+ */
const useUserSessionTimeout = () => {
+ const gmp = useGmp();
const dispatch = useDispatch();
- return [
- useSelector(getSessionTimeout),
- timeout => dispatch(setSessionTimeout(timeout)),
- ];
+ const sessionTimeout = useSelector(getSessionTimeout);
+
+ const renewSessionAndUpdateTimeout = async () => {
+ const response = await gmp.user.renewSession();
+ dispatch(setSessionTimeout(response.data));
+ };
+
+ return [sessionTimeout, renewSessionAndUpdateTimeout];
};
export default useUserSessionTimeout;