From 3e441fd3bdfd37c163fb57796e9dd7da37055fcb Mon Sep 17 00:00:00 2001 From: Andrii Podriez Date: Wed, 31 Jul 2024 19:27:10 +0200 Subject: [PATCH] updated login logic Signed-off-by: Andrii Podriez --- src/app.js | 19 +- src/common/menu.js | 10 +- src/pages/account/account.js | 3 +- src/pages/infrastructure/ic-category-table.js | 3 +- .../ic-pages/default-ic-page.js | 12 +- .../ic-pages/default-manager-page.js | 8 +- .../ic-pages/gateway-villas-node.js | 7 +- .../ic-pages/kubernetes-ic-page.js | 11 +- .../ic-pages/manager-villas-node.js | 9 +- .../ic-pages/manager-villas-relay.js | 4 +- src/pages/infrastructure/ic.js | 5 +- src/pages/infrastructure/infrastructure.js | 6 +- src/pages/login/login-form.js | 37 ++- src/pages/login/login.js | 7 +- src/pages/login/logout.js | 4 +- src/pages/scenarios/scenario.js | 5 +- src/pages/scenarios/scenarios.js | 6 +- src/pages/scenarios/tables/configs-table.js | 4 +- .../scenarios/tables/dashboards-table.js | 4 +- src/pages/scenarios/tables/results-table.js | 6 - src/pages/scenarios/tables/users-table.js | 4 +- src/pages/users/users.js | 4 +- src/store/apiSlice.js | 267 ++---------------- src/store/authSlice.js | 72 +++++ src/store/endpoints/auth-endpoints.js | 26 ++ src/store/endpoints/config-endpoints.js | 38 +++ src/store/endpoints/dashboard-endpoints.js | 45 +++ src/store/endpoints/file-endpoints.js | 60 ++++ src/store/endpoints/ic-endpoints.js | 29 ++ src/store/endpoints/result-endpoints.js | 38 +++ src/store/endpoints/scenario-endpoints.js | 60 ++++ src/store/endpoints/signal-endpoints.js | 38 +++ src/store/endpoints/user-endpoints.js | 45 +++ src/store/endpoints/widget-endpoints.js | 48 ++++ src/store/index.js | 2 + 35 files changed, 621 insertions(+), 325 deletions(-) create mode 100644 src/store/authSlice.js create mode 100644 src/store/endpoints/auth-endpoints.js create mode 100644 src/store/endpoints/config-endpoints.js create mode 100644 src/store/endpoints/dashboard-endpoints.js create mode 100644 src/store/endpoints/file-endpoints.js create mode 100644 src/store/endpoints/ic-endpoints.js create mode 100644 src/store/endpoints/result-endpoints.js create mode 100644 src/store/endpoints/scenario-endpoints.js create mode 100644 src/store/endpoints/signal-endpoints.js create mode 100644 src/store/endpoints/user-endpoints.js create mode 100644 src/store/endpoints/widget-endpoints.js diff --git a/src/app.js b/src/app.js index 571abf7..510a649 100644 --- a/src/app.js +++ b/src/app.js @@ -37,20 +37,25 @@ import './styles/login.css'; import branding from './branding/branding'; import Logout from './pages/login/logout'; import Infrastructure from './pages/infrastructure/infrastructure'; -import { currentUser, sessionToken } from './localStorage'; +import { useSelector } from 'react-redux'; const App = () => { const isTokenExpired = (token) => { + console.log("decoded, ", jwt.decode(token)) let decodedToken = jwt.decode(token); let timeNow = (new Date().getTime() + 1) / 1000; return decodedToken.exp < timeNow; } - if ((sessionToken == null || sessionToken === "" || currentUser == null || currentUser === "") || isTokenExpired(sessionToken)) { - console.log("APP redirecting to logout/login") + const { isAuthenticated, token, user } = useSelector((state) => state.auth); + + if (!isAuthenticated || isTokenExpired(token)) { + console.log("APP redirecting to logout/login"); return (); } else { + + console.log("APP rendering app"); const pages = branding.values.pages; return ( @@ -59,7 +64,7 @@ const App = () => {
- +
@@ -82,7 +87,7 @@ const App = () => { : '' } - { currentUser.role === "Admin" || pages.infrastructure ? <> + { user.role === "Admin" || pages.infrastructure ? <> @@ -92,12 +97,12 @@ const App = () => { : '' } { pages.account ? : '' } - { currentUser.role === "Admin" ? + { user.role === "Admin" ? : '' } - { currentUser.role === "Admin" || pages.api ? + { user.role === "Admin" || pages.api ? : '' }
diff --git a/src/common/menu.js b/src/common/menu.js index 93488a1..b30eb1c 100644 --- a/src/common/menu.js +++ b/src/common/menu.js @@ -20,13 +20,15 @@ import { useEffect, useState } from 'react'; import { NavLink } from 'react-router-dom'; import branding from '../branding/branding'; import { useGetConfigQuery } from '../store/apiSlice'; -import { currentUser } from '../localStorage'; +import { useSelector } from 'react-redux'; const SideBarMenu = (props) => { const values = branding.values; const [isExternalAuth, setIsExternalAuth] = useState(false); const [logoutLink, setLogoutLink] = useState(''); + + const { user: currentUser } = useSelector((state) => state.auth); const {data: configRes} = useGetConfigQuery(); @@ -34,11 +36,7 @@ const SideBarMenu = (props) => { if(configRes) { setLogoutLink(configRes.authentication.logout_url); } - }, [configRes]) - - const logout = async () => { - - } + }, [configRes]); const getLinks = () => { let links = []; diff --git a/src/pages/account/account.js b/src/pages/account/account.js index d3401a5..966de16 100644 --- a/src/pages/account/account.js +++ b/src/pages/account/account.js @@ -16,10 +16,10 @@ ******************************************************************************/ import { useState } from "react"; +import { useSelector } from "react-redux"; import IconButton from "../../common/buttons/icon-button"; import { Form, Row, Col } from 'react-bootstrap'; import EditOwnUserDialog from "./edit-own-user"; -import { currentUser } from "../../localStorage"; import NotificationsFactory from "../../common/data-managers/notifications-factory"; import notificationsDataManager from "../../common/data-managers/notifications-data-manager"; import { useUpdateUserMutation } from "../../store/apiSlice"; @@ -28,6 +28,7 @@ const Account = () => { const [isEditModalOpened, setIsEditModalOpened] = useState(false); const [updateUser] = useUpdateUserMutation(); + const { user: currentUser } = useSelector((state) => state.auth); const buttonStyle = { marginLeft: '10px', diff --git a/src/pages/infrastructure/ic-category-table.js b/src/pages/infrastructure/ic-category-table.js index 3e3a38a..59cd821 100644 --- a/src/pages/infrastructure/ic-category-table.js +++ b/src/pages/infrastructure/ic-category-table.js @@ -26,7 +26,6 @@ import moment from 'moment' import IconToggleButton from "../../common/buttons/icon-toggle-button"; import { updateCheckedICs, openDeleteModal, openEditModal } from "../../store/icSlice"; import { stateLabelStyle } from "./styles"; -import { currentUser } from "../../localStorage"; //a Table of IC components of specific category from props.category //titled with props.title @@ -35,6 +34,8 @@ const ICCategoryTable = (props) => { const ics = useSelector(state => state.infrastructure.ICsArray); const [isGenericDisplayed, setIsGenericDisplayed] = useState(false); + const { user: currentUser } = useSelector((state) => state.auth); + const modifyUptimeColumn = (uptime, component) => { if (uptime >= 0) { let momentDurationFormatSetup = require("moment-duration-format"); diff --git a/src/pages/infrastructure/ic-pages/default-ic-page.js b/src/pages/infrastructure/ic-pages/default-ic-page.js index 674f6fb..17b75f0 100644 --- a/src/pages/infrastructure/ic-pages/default-ic-page.js +++ b/src/pages/infrastructure/ic-pages/default-ic-page.js @@ -15,18 +15,12 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; +import { useSelector } from "react-redux"; import {Col, Row} from "react-bootstrap"; import IconButton from '../../../common/buttons/icon-button'; -import ManagedICsTable from "./managed-ics-table"; - import { useDispatch } from 'react-redux'; import { loadICbyId } from '../../../store/icSlice'; -import { sessionToken, currentUser } from '../../../localStorage'; -import { loadConfig } from '../../../store/configSlice'; -import { useSelector } from 'react-redux'; -import {refresh, rawDataTable} from "../ic" - import ICParamsTable from '../ic-params-table'; import RawDataTable from '../../../common/rawDataTable'; @@ -35,6 +29,8 @@ import { iconStyle, buttonStyle } from "../styles"; const DefaultICPage = (props) => { const ic = props.ic; + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const dispatch = useDispatch(); const refresh = () => { diff --git a/src/pages/infrastructure/ic-pages/default-manager-page.js b/src/pages/infrastructure/ic-pages/default-manager-page.js index 79324ad..2210c53 100644 --- a/src/pages/infrastructure/ic-pages/default-manager-page.js +++ b/src/pages/infrastructure/ic-pages/default-manager-page.js @@ -16,16 +16,12 @@ ******************************************************************************/ import React, { useEffect, useState } from 'react'; +import { useSelector } from "react-redux"; import {Col, Row} from "react-bootstrap"; import IconButton from '../../../common/buttons/icon-button'; import ManagedICsTable from "./managed-ics-table"; - import { useDispatch } from 'react-redux'; import { loadICbyId } from '../../../store/icSlice'; -import { sessionToken, currentUser } from '../../../localStorage'; -import { loadConfig } from '../../../store/configSlice'; -import { useSelector } from 'react-redux'; -import {refresh, rawDataTable} from "../ic" import ICParamsTable from '../ic-params-table'; import RawDataTable from '../../../common/rawDataTable'; @@ -37,6 +33,8 @@ const DefaultManagerPage = (props) => { const ics = useSelector((state) => state.infrastructure.ICsArray); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const dispatch = useDispatch(); const managedICs = ics.filter(managedIC => managedIC.category !== "manager" && managedIC.manager === ic.uuid); diff --git a/src/pages/infrastructure/ic-pages/gateway-villas-node.js b/src/pages/infrastructure/ic-pages/gateway-villas-node.js index 8e78223..e3808bf 100644 --- a/src/pages/infrastructure/ic-pages/gateway-villas-node.js +++ b/src/pages/infrastructure/ic-pages/gateway-villas-node.js @@ -1,13 +1,10 @@ import { useState } from "react"; +import { useSelector } from "react-redux"; import { useDispatch } from "react-redux"; - import ICParamsTable from "../ic-params-table"; import RawDataTable from '../../../common/rawDataTable'; - import { restartIC, shutdownIC, loadICbyId } from "../../../store/icSlice"; -import { sessionToken, currentUser } from "../../../localStorage"; import { buttonStyle, iconStyle } from "../styles"; - import IconButton from "../../../common/buttons/icon-button"; import {Button, Col, Container, Row} from "react-bootstrap"; import ConfirmCommand from "../../../common/confirm-command"; @@ -20,6 +17,8 @@ const GatewayVillasNode = (props) => { const [command, setCommand] = useState(""); const [isCommandConfirmed, setIsCommandConfirmed] = useState(false); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const sendControlCommand = () => { switch(command){ case "restart": diff --git a/src/pages/infrastructure/ic-pages/kubernetes-ic-page.js b/src/pages/infrastructure/ic-pages/kubernetes-ic-page.js index 18873b9..80d8942 100644 --- a/src/pages/infrastructure/ic-pages/kubernetes-ic-page.js +++ b/src/pages/infrastructure/ic-pages/kubernetes-ic-page.js @@ -15,16 +15,11 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import { useState, useEffect } from "react"; -import { Col, Row, Container, Table } from "react-bootstrap"; +import { Col, Row } from "react-bootstrap"; import IconButton from "../../../common/buttons/icon-button"; -import ManagedICsTable from "./managed-ics-table"; -import FileSaver from 'file-saver'; import RawDataTable from "../../../common/rawDataTable"; -import { downloadGraph } from "../../../utils/icUtils"; -import { sessionToken, currentUser } from "../../../localStorage"; import { useDispatch, useSelector } from "react-redux"; -import { loadAllICs, loadICbyId } from "../../../store/icSlice"; +import { loadICbyId } from "../../../store/icSlice"; import ICParamsTable from "../ic-params-table"; @@ -34,6 +29,8 @@ const KubernetesICPage = (props) => { const dispatch = useDispatch(); + + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); const ic = props.ic; const ics = useSelector((state) => state.infrastructure.ICsArray); diff --git a/src/pages/infrastructure/ic-pages/manager-villas-node.js b/src/pages/infrastructure/ic-pages/manager-villas-node.js index 6221c17..0446e77 100644 --- a/src/pages/infrastructure/ic-pages/manager-villas-node.js +++ b/src/pages/infrastructure/ic-pages/manager-villas-node.js @@ -15,16 +15,13 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import { useState, useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; import { Col, Row } from "react-bootstrap"; import IconButton from "../../../common/buttons/icon-button"; import ManagedICsTable from "./managed-ics-table"; -import FileSaver from 'file-saver'; import RawDataTable from "../../../common/rawDataTable"; import { downloadGraph } from "../../../utils/icUtils"; -import { sessionToken, currentUser } from "../../../localStorage"; -import { useDispatch, useSelector } from "react-redux"; -import { loadAllICs, loadICbyId } from "../../../store/icSlice"; +import { loadICbyId } from "../../../store/icSlice"; import ICParamsTable from "../ic-params-table"; @@ -32,6 +29,8 @@ import { iconStyle, buttonStyle } from "../styles"; const ManagerVillasNode = (props) => { + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const dispatch = useDispatch(); const ic = props.ic; diff --git a/src/pages/infrastructure/ic-pages/manager-villas-relay.js b/src/pages/infrastructure/ic-pages/manager-villas-relay.js index 92f1d6f..f4f4c0e 100644 --- a/src/pages/infrastructure/ic-pages/manager-villas-relay.js +++ b/src/pages/infrastructure/ic-pages/manager-villas-relay.js @@ -15,12 +15,10 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import { useState, useEffect } from "react"; import { Col, Row, Container } from "react-bootstrap"; import IconButton from "../../../common/buttons/icon-button"; import ManagedICsTable from "./managed-ics-table"; import RawDataTable from "../../../common/rawDataTable"; -import { sessionToken, currentUser } from "../../../localStorage"; import { useDispatch, useSelector } from "react-redux"; import { loadAllICs, loadICbyId } from "../../../store/icSlice"; @@ -32,6 +30,8 @@ const ManagerVillasRelay = (props) => { const dispatch = useDispatch(); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const ic = props.ic; const ics = useSelector((state) => state.infrastructure.ICsArray); diff --git a/src/pages/infrastructure/ic.js b/src/pages/infrastructure/ic.js index d7b3d2a..51480d2 100644 --- a/src/pages/infrastructure/ic.js +++ b/src/pages/infrastructure/ic.js @@ -15,8 +15,7 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import { useEffect, useRef } from "react"; -import { sessionToken, currentUser } from "../../localStorage"; +import { useEffect } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useParams } from 'react-router-dom'; import { loadAllICs, loadICbyId } from "../../store/icSlice"; @@ -34,6 +33,8 @@ const InfrastructureComponent = (props) => { const id = params.ic; const dispatch = useDispatch(); + const { token: sessionToken } = useSelector((state) => state.auth); + const ic = useSelector(state => state.infrastructure.currentIC); const isICLoading = useSelector(state => state.infrastructure.isCurrentICLoading); diff --git a/src/pages/infrastructure/infrastructure.js b/src/pages/infrastructure/infrastructure.js index 92d9018..af2a1fe 100644 --- a/src/pages/infrastructure/infrastructure.js +++ b/src/pages/infrastructure/infrastructure.js @@ -16,12 +16,10 @@ ******************************************************************************/ import { useEffect, useState } from "react" -import { useDispatch } from "react-redux"; -import { useSelector } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { loadAllICs, loadICbyId, addIC, sendActionToIC, closeDeleteModal, closeEditModal, editIC, deleteIC } from "../../store/icSlice"; import IconButton from "../../common/buttons/icon-button"; import ICCategoryTable from "./ic-category-table"; -import { sessionToken, currentUser } from "../../localStorage"; import ICActionBoard from "./ic-action-board"; import { buttonStyle, iconStyle } from "./styles"; import NewICDialog from "./dialogs/new-ic-dialog"; @@ -35,6 +33,8 @@ import NotificationsFactory from "../../common/data-managers/notifications-facto const Infrastructure = (props) => { const dispatch = useDispatch(); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const ics = useSelector(state => state.infrastructure.ICsArray); const externalICs = ics.filter(ic => ic.managedexternally === true); diff --git a/src/pages/login/login-form.js b/src/pages/login/login-form.js index d4cca3b..b40674d 100644 --- a/src/pages/login/login-form.js +++ b/src/pages/login/login-form.js @@ -15,27 +15,48 @@ * along with VILLASweb. If not, see . ******************************************************************************/ -import React, { useState, useEffect } from 'react'; +import React, { useState } from 'react'; import { Form, Button, Col } from 'react-bootstrap'; import { useDispatch } from 'react-redux'; -import { login } from '../../store/userSlice'; import _ from 'lodash'; -import { sessionToken } from '../../localStorage'; import RecoverPassword from './recover-password'; +import NotificationsFactory from '../../common/data-managers/notifications-factory'; +import notificationsDataManager from '../../common/data-managers/notifications-data-manager'; +import { useAuthenticateUserMutation } from '../../store/apiSlice'; +import { setUser } from '../../store/authSlice'; -const LoginForm = ({loginMessage, config}) => { +const LoginForm = ({config}) => { + const dispatch = useDispatch(); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); - const [forgottenPassword, setForgottenPassword] = useState(false) + const [forgottenPassword, setForgottenPassword] = useState(false); + const [loginMessage, setLoginMessage] = useState(''); + const [authenticationRequest] = useAuthenticateUserMutation(); //this variable is used to disable login button if either username or password is empty const isInputValid = username !== '' && password !== ''; - const dispatch = useDispatch(); - const loginEvent = (event) => { event.preventDefault(); - dispatch(login({username, password})) + authenticateUser(); + } + + const authenticateUser = async () => { + try { + const res = await authenticationRequest({mechanism: "internal", username: username, password: password}); + if(res.error) { + setLoginMessage(res.error.data.message); + } else { + dispatch(setUser({user: res.data.user, token: res.data.token})); + setLoginMessage(''); + } + } catch (err) { + if(err.data){ + notificationsDataManager.addNotification(NotificationsFactory.UPDATE_ERROR(err.data.message)); + } else { + console.log('Error', err); + } + } } const villasLogin = ( diff --git a/src/pages/login/login.js b/src/pages/login/login.js index 5190136..115f50b 100644 --- a/src/pages/login/login.js +++ b/src/pages/login/login.js @@ -36,10 +36,9 @@ const Login = (props) => { const {data: config} = useGetConfigQuery(); - const currentUser = useSelector(state => state.user.currentUser); - const loginMessage = useSelector(state => state.user.loginMessage); + const { isAuthenticated } = useSelector((state) => state.auth); - return currentUser == null ? + return !isAuthenticated ? (
@@ -52,7 +51,7 @@ const Login = (props) => {
Login - +
diff --git a/src/pages/login/logout.js b/src/pages/login/logout.js index d6b2741..83e9c8d 100644 --- a/src/pages/login/logout.js +++ b/src/pages/login/logout.js @@ -18,7 +18,7 @@ import React, {useEffect} from 'react'; import { Redirect } from 'react-router-dom'; import { useDispatch } from 'react-redux' -import { logout } from '../../store/userSlice'; +import { deleteUser } from '../../store/authSlice'; const Logout = () => { @@ -26,7 +26,7 @@ const Logout = () => { useEffect(() => { let isMounted = true; - if(isMounted) dispatch(logout()); + if(isMounted) dispatch(deleteUser()); return () => {isMounted = false}; }, []); diff --git a/src/pages/scenarios/scenario.js b/src/pages/scenarios/scenario.js index 86283e1..ed63521 100644 --- a/src/pages/scenarios/scenario.js +++ b/src/pages/scenarios/scenario.js @@ -16,14 +16,13 @@ ******************************************************************************/ import { useParams } from "react-router-dom/cjs/react-router-dom.min"; +import { useSelector } from "react-redux"; import { useGetScenarioByIdQuery } from "../../store/apiSlice"; import IconButton from "../../common/buttons/icon-button"; -import { currentUser, sessionToken } from "../../localStorage"; import IconToggleButton from "../../common/buttons/icon-toggle-button"; import ConfigsTable from "./tables/configs-table"; import DashboardsTable from "./tables/dashboards-table"; import ResultsTable from "./tables/results-table"; -import { tableHeadingStyle } from "./styles"; import UsersTable from "./tables/users-table"; import { useUpdateScenarioMutation, @@ -34,6 +33,8 @@ const Scenario = (props) => { const params = useParams(); const id = params.scenario; + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const { data: fetchedScenarios, isLoading: isScenarioLoading, refetch: refetchScenario } = useGetScenarioByIdQuery(id); const scenario = fetchedScenarios?.scenario; diff --git a/src/pages/scenarios/scenarios.js b/src/pages/scenarios/scenarios.js index 51d138c..42e96fb 100644 --- a/src/pages/scenarios/scenarios.js +++ b/src/pages/scenarios/scenarios.js @@ -16,11 +16,9 @@ ******************************************************************************/ import { useState } from "react"; -import { useDispatch } from "react-redux"; import IconButton from "../../common/buttons/icon-button"; import { Table, ButtonColumn, DataColumn, LinkColumn } from "../../common/table"; import { buttonStyle, iconStyle } from "./styles"; -import { currentUser } from "../../localStorage"; import NewScenarioDialog from "./dialogs/new-scenario"; import ImportScenarioDialog from "./dialogs/import-scenario"; import DeleteDialog from "../../common/dialogs/delete-dialog"; @@ -34,12 +32,14 @@ import { useGetConfigsQuery, useGetDashboardsQuery, } from "../../store/apiSlice"; +import { useSelector } from "react-redux"; const Scenarios = (props) => { const { data , error, refetch: refetchScenarios } = useGetScenariosQuery(); const scenarios = data?.scenarios; - const dispatch = useDispatch(); + + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); const [modalScenario, setModalScenario] = useState({name: 'error'}); const [isNewModalOpened, setIsNewModalOpened] = useState(false); diff --git a/src/pages/scenarios/tables/configs-table.js b/src/pages/scenarios/tables/configs-table.js index 2b0806b..bb171b0 100644 --- a/src/pages/scenarios/tables/configs-table.js +++ b/src/pages/scenarios/tables/configs-table.js @@ -16,10 +16,10 @@ ******************************************************************************/ import { useState, useEffect } from "react"; +import { useSelector } from "react-redux"; import IconButton from "../../../common/buttons/icon-button"; import { Table, ButtonColumn, CheckboxColumn, DataColumn } from "../../../common/table"; import { tableHeadingStyle, buttonStyle, iconStyle } from "../styles"; -import { currentUser, sessionToken } from "../../../localStorage"; import NewDialog from "../../../common/dialogs/new-dialog"; import ImportConfigDialog from "../dialogs/import-config"; import DeleteDialog from "../../../common/dialogs/delete-dialog"; @@ -56,6 +56,8 @@ const ConfigsTable = ({scenario, ics}) => { const [checkedConfigsIDs, setCheckedConfigsIDs] = useState([]); const [areAllConfigsChecked, setAreAllConfigsChecked] = useState(false); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + useEffect(() => { if(configs.length > 0) { configs.forEach(config => { diff --git a/src/pages/scenarios/tables/dashboards-table.js b/src/pages/scenarios/tables/dashboards-table.js index f6ac81b..f50eac9 100644 --- a/src/pages/scenarios/tables/dashboards-table.js +++ b/src/pages/scenarios/tables/dashboards-table.js @@ -16,10 +16,10 @@ ******************************************************************************/ import { useState } from "react"; +import { useSelector } from "react-redux"; import IconButton from "../../../common/buttons/icon-button"; import { Table, ButtonColumn, LinkColumn, DataColumn } from "../../../common/table"; import { buttonStyle, tableHeadingStyle, iconStyle } from "../styles"; -import { currentUser, sessionToken } from "../../../localStorage"; import { InputGroup, Form } from "react-bootstrap"; import { useGetDashboardsQuery } from "../../../store/apiSlice"; import {Button} from "react-bootstrap"; @@ -46,6 +46,8 @@ const DashboardsTable = ({scenario}) => { const [updateDashboard] = useUpdateDashboardMutation(); const [addWidgetToDashboard] = useAddWidgetMutation(); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const [triggerGetWidgets, { isLoading: isWidgetsLoading, data: widgets, error: widgetsError }] = useLazyGetWidgetsQuery(); const dashboards = fetchedDashboards ? fetchedDashboards.dashboards : []; diff --git a/src/pages/scenarios/tables/results-table.js b/src/pages/scenarios/tables/results-table.js index 02e43e3..f0ff497 100644 --- a/src/pages/scenarios/tables/results-table.js +++ b/src/pages/scenarios/tables/results-table.js @@ -19,8 +19,6 @@ import { useState, useEffect } from "react"; import IconButton from "../../../common/buttons/icon-button"; import { Table, ButtonColumn, DataColumn, LinkbuttonColumn } from "../../../common/table"; import { buttonStyle, tableHeadingStyle, iconStyle } from "../styles"; -import { currentUser, sessionToken } from "../../../localStorage"; -import { InputGroup, Form } from "react-bootstrap"; import DeleteDialog from "../../../common/dialogs/delete-dialog"; import ResultConfigDialog from "../dialogs/result-configs-dialog"; import ResultPythonDialog from "../dialogs/result-python-dialog"; @@ -34,12 +32,8 @@ import { useAddResultMutation, useDeleteResultMutation, useGetFilesQuery, - useAddFileMutation, useLazyDownloadFileQuery, - useUpdateFileMutation, - useDeleteFileMutation, } from "../../../store/apiSlice"; -import { set } from "lodash"; import JSZip from 'jszip'; const ResultsTable = (props) => { diff --git a/src/pages/scenarios/tables/users-table.js b/src/pages/scenarios/tables/users-table.js index dda72a0..ccfb06c 100644 --- a/src/pages/scenarios/tables/users-table.js +++ b/src/pages/scenarios/tables/users-table.js @@ -16,10 +16,10 @@ ******************************************************************************/ import { useState } from "react"; +import { useSelector } from "react-redux"; import IconButton from "../../../common/buttons/icon-button"; import { Table, ButtonColumn, DataColumn } from "../../../common/table"; import { buttonStyle, tableHeadingStyle } from "../styles"; -import { currentUser } from "../../../localStorage"; import { InputGroup, Form } from "react-bootstrap"; import DeleteDialog from "../../../common/dialogs/delete-dialog"; import NotificationsFactory from "../../../common/data-managers/notifications-factory"; @@ -36,6 +36,8 @@ const UsersTable = (props) => { const [usernameToAdd, setUsernameToAdd] = useState(""); const [usernameToDelete, setUsernameToDelete] = useState(""); + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const addUser = async () => { if(usernameToAdd.trim() === ''){ notificationsDataManager.addNotification(NotificationsFactory.LOAD_ERROR('Please, enter correct username')); diff --git a/src/pages/users/users.js b/src/pages/users/users.js index 8d98374..b5890de 100644 --- a/src/pages/users/users.js +++ b/src/pages/users/users.js @@ -1,4 +1,5 @@ import { useState } from "react"; +import { useSelector } from "react-redux"; import { Dropdown, DropdownButton } from 'react-bootstrap'; import { Table, ButtonColumn, CheckboxColumn, DataColumn } from "../../common/table"; import Icon from "../../common/icon"; @@ -8,7 +9,6 @@ import EditUserDialog from "./dialogs/edit-user"; import UsersToScenarioDialog from "./dialogs/users-to-scenario"; import DeleteDialog from "../../common/dialogs/delete-dialog"; import { buttonStyle, iconStyle } from "./styles"; -import {currentUser} from '../../localStorage'; import NotificationsFactory from "../../common/data-managers/notifications-factory"; import notificationsDataManager from "../../common/data-managers/notifications-data-manager"; import { @@ -22,6 +22,8 @@ import { const Users = ({}) => { + const { user: currentUser, token: sessionToken } = useSelector((state) => state.auth); + const {data: fetchedUsers, refetch: refetchUsers} = useGetUsersQuery(); const users = fetchedUsers ? fetchedUsers.users : []; const { data: fetchedScenarios } = useGetScenariosQuery(); diff --git a/src/store/apiSlice.js b/src/store/apiSlice.js index 4361ab6..dac5b23 100644 --- a/src/store/apiSlice.js +++ b/src/store/apiSlice.js @@ -1,8 +1,18 @@ import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import { sessionToken } from '../localStorage'; +import { widgetEndpoints } from './endpoints/widget-endpoints'; +import { scenarioEndpoints } from './endpoints/scenario-endpoints'; +import { dashboardEndpoints } from './endpoints/dashboard-endpoints'; +import { icEndpoints } from './endpoints/ic-endpoints'; +import { configEndpoints } from './endpoints/config-endpoints'; +import { userEndpoints } from './endpoints/user-endpoints'; +import { fileEndpoints } from './endpoints/file-endpoints'; +import { signalEndpoints } from './endpoints/signal-endpoints'; +import { resultEndpoints } from './endpoints/result-endpoints'; +import { authEndpoints } from './endpoints/auth-endpoints'; export const apiSlice = createApi({ - reducerPath: 'scenarios', + reducerPath: 'api', baseQuery: fetchBaseQuery({ baseUrl: '/api/v2', prepareHeaders: (headers) => { @@ -14,244 +24,16 @@ export const apiSlice = createApi({ }, }), endpoints: (builder) => ({ - getScenarios: builder.query({ - query: () => 'scenarios', - }), - getScenarioById: builder.query({ - query: (id) => `scenarios/${id}`, - }), - addScenario: builder.mutation({ - query: (scenario) => ({ - url: 'scenarios', - method: 'POST', - body: scenario, - }), - }), - deleteScenario: builder.mutation({ - query: (id) => ({ - url: `scenarios/${id}`, - method: 'DELETE', - }), - }), - updateScenario: builder.mutation({ - query: ({ id, ...updatedScenario }) => ({ - url: `scenarios/${id}`, - method: 'PUT', - body: updatedScenario, - }), - }), - getConfigs: builder.query({ - query: (scenarioID) => `configs?scenarioID=${scenarioID}`, - }), - getUsersOfScenario: builder.query({ - query: (scenarioID) => `scenarios/${scenarioID}/users/`, - }), - getDashboards: builder.query({ - query: (scenarioID) => `dashboards?scenarioID=${scenarioID}`, - }), - getICS: builder.query({ - query: () => 'ic', - }), - addUserToScenario: builder.mutation({ - query: ({ scenarioID, username }) => { - return ({ - url: `scenarios/${scenarioID}/user?username=${username}`, - method: 'PUT', - })}, - }), - removeUserFromScenario: builder.mutation({ - query: ({ scenarioID, username }) => ({ - url: `scenarios/${scenarioID}/user/?username=${username}`, - method: 'DELETE', - }), - }), - addComponentConfig: builder.mutation({ - query: (config) => ({ - url: 'configs', - method: 'POST', - body: config, - }), - }), - deleteComponentConfig: builder.mutation({ - query: (configID) => ({ - url: `configs/${configID}`, - method: 'DELETE', - }), - }), - addDashboard: builder.mutation({ - query: (dashboard) => ({ - url: 'dashboards', - method: 'POST', - body: dashboard, - }), - }), - deleteDashboard: builder.mutation({ - query: (dashboardID) => ({ - url: `dashboards/${dashboardID}`, - method: 'DELETE', - }), - }), - updateDashboard: builder.mutation({ - query: ({ dashboardID, dashboard }) => ({ - url: `dashboards/${dashboardID}`, - method: 'PUT', - body: {dashboard}, - }), - }), - getSignals: builder.query({ - query: ({ direction, configID }) => ({ - url: 'signals', - params: { direction, configID }, - }), - }), - addSignal: builder.mutation({ - query: (signal) => ({ - url: 'signals', - method: 'POST', - body: { signal }, - }), - }), - deleteSignal: builder.mutation({ - query: (signalID) => ({ - url: `signals/${signalID}`, - method: 'DELETE', - }), - }), - //users - getUsers: builder.query({ - query: () => 'users', - }), - getUserById: builder.query({ - query: (id) => `users/${id}`, - }), - addUser: builder.mutation({ - query: (user) => ({ - url: 'users', - method: 'POST', - body: user, - }), - }), - updateUser: builder.mutation({ - query: (user) => { - return { - url: `users/${user.id}`, - method: 'PUT', - body: {user: user}, - }}, - }), - deleteUser: builder.mutation({ - query: (id) => ({ - url: `users/${id}`, - method: 'DELETE', - }), - }), - //results - getResults: builder.query({ - query: (scenarioID) => ({ - url: 'results', - params: { scenarioID }, - }), - }), - addResult: builder.mutation({ - query: (result) => ({ - url: 'results', - method: 'POST', - body: result, - }), - }), - deleteResult: builder.mutation({ - query: (resultID) => ({ - url: `results/${resultID}`, - method: 'DELETE', - }), - }), - //files - getFiles: builder.query({ - query: (scenarioID) => ({ - url: 'files', - params: { scenarioID }, - }), - }), - addFile: builder.mutation({ - query: ({ scenarioID, file }) => { - const formData = new FormData(); - formData.append('inputFile', file); - return { - url: `files?scenarioID=${scenarioID}`, - method: 'POST', - body: formData, - }; - }, - }), - downloadFile: builder.query({ - query: (fileID) => ({ - url: `files/${fileID}`, - responseHandler: 'blob', - responseType: 'blob', - }), - }), - updateFile: builder.mutation({ - query: ({ fileID, file }) => { - const formData = new FormData(); - formData.append('inputFile', file); - return { - url: `files/${fileID}`, - method: 'PUT', - body: formData, - }; - }, - }), - deleteFile: builder.mutation({ - query: (fileID) => ({ - url: `files/${fileID}`, - method: 'DELETE', - }), - }), - sendAction: builder.mutation({ - query: (params) => ({ - url: `/ic/${params.icid}/action`, - method: 'POST', - body: [params], - }), - }), - - getDashboard: builder.query({ - query: (dashboardID) => `/dashboards/${dashboardID}`, - }), - - getWidgets: builder.query({ - query: (dashboardID) => ({ - url: 'widgets', - params: { dashboardID }, - }), - }), - addWidget: builder.mutation({ - query: (widget) => ({ - url: 'widgets', - method: 'POST', - body: { widget }, - }), - }), - getWidget: builder.query({ - query: (widgetID) => `/widgets/${widgetID}`, - }), - updateWidget: builder.mutation({ - query: ({ widgetID, updatedWidget }) => ({ - url: `/widgets/${widgetID}`, - method: 'PUT', - body: updatedWidget, - }), - }), - deleteWidget: builder.mutation({ - query: (widgetID) => ({ - url: `/widgets/${widgetID}`, - method: 'DELETE', - }), - }), - - getConfig: builder.query({ - query: () => '/config', - }) + ...widgetEndpoints(builder), + ...icEndpoints(builder), + ...fileEndpoints(builder), + ...configEndpoints(builder), + ...scenarioEndpoints(builder), + ...dashboardEndpoints(builder), + ...userEndpoints(builder), + ...resultEndpoints(builder), + ...signalEndpoints(builder), + ...authEndpoints(builder), }), }); @@ -276,31 +58,26 @@ export const { useGetSignalsQuery, useAddSignalMutation, useDeleteSignalMutation, - useGetResultsQuery, useAddResultMutation, useDeleteResultMutation, - useGetUsersQuery, useGetUserByIdQuery, useAddUserMutation, useUpdateUserMutation, useDeleteUserMutation, - useGetFilesQuery, useAddFileMutation, useLazyDownloadFileQuery, useUpdateFileMutation, useDeleteFileMutation, - useGetDashboardQuery, useUpdateDashboardMutation, - useSendActionMutation, - useAddWidgetMutation, useLazyGetWidgetsQuery, useUpdateWidgetMutation, useDeleteWidgetMutation, useGetConfigQuery, + useAuthenticateUserMutation, } = apiSlice; diff --git a/src/store/authSlice.js b/src/store/authSlice.js new file mode 100644 index 0000000..b0cf1f1 --- /dev/null +++ b/src/store/authSlice.js @@ -0,0 +1,72 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +import { createSlice } from '@reduxjs/toolkit'; +import { apiSlice } from './apiSlice'; +import { sessionToken, currentUser } from '../localStorage'; + +const initialState = { + user: currentUser, + token: sessionToken, + isAuthenticated: sessionToken && currentUser, + error: null, +}; + +const authSlice = createSlice({ + name: 'auth', + initialState, + reducers: { + setUser: (state, action) => { + console.log("setting up storage", action.payload.user, action.payload.token) + localStorage.setItem('currentUser', JSON.stringify(action.payload.user)); + localStorage.setItem('token', action.payload.token); + state.user = action.payload.user; + state.token = action.payload.token; + state.isAuthenticated = true; + state.error = null; + }, + deleteUser: (state) => { + state.user = null; + state.user = null; + state.token = null; + state.isAuthenticated = false; + state.error = null; + localStorage.clear(); + } + }, + extraReducers: (builder) => { + builder.addMatcher( + apiSlice.endpoints.authenticateUser.matchFulfilled, + (state, { payload }) => { + state.user = payload.user; + state.token = payload.token; + state.isAuthenticated = true; + state.error = null; + } + ); + builder.addMatcher( + apiSlice.endpoints.authenticateUser.matchRejected, + (state, { error }) => { + state.error = error; + } + ); + }, +}); + +export const { setUser, deleteUser } = authSlice.actions; + +export default authSlice.reducer; \ No newline at end of file diff --git a/src/store/endpoints/auth-endpoints.js b/src/store/endpoints/auth-endpoints.js new file mode 100644 index 0000000..6facff4 --- /dev/null +++ b/src/store/endpoints/auth-endpoints.js @@ -0,0 +1,26 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const authEndpoints = (builder) => ({ + authenticateUser: builder.mutation({ + query: ({ mechanism, ...loginRequest }) => ({ + url: `authenticate/${mechanism}`, + method: 'POST', + body: loginRequest, + }), + }), +}); diff --git a/src/store/endpoints/config-endpoints.js b/src/store/endpoints/config-endpoints.js new file mode 100644 index 0000000..7141d1e --- /dev/null +++ b/src/store/endpoints/config-endpoints.js @@ -0,0 +1,38 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const configEndpoints = (builder) => ({ + getConfigs: builder.query({ + query: (scenarioID) => `configs?scenarioID=${scenarioID}`, + }), + addComponentConfig: builder.mutation({ + query: (config) => ({ + url: 'configs', + method: 'POST', + body: config, + }), + }), + deleteComponentConfig: builder.mutation({ + query: (configID) => ({ + url: `configs/${configID}`, + method: 'DELETE', + }), + }), + getConfig: builder.query({ + query: () => '/config', + }), +}); diff --git a/src/store/endpoints/dashboard-endpoints.js b/src/store/endpoints/dashboard-endpoints.js new file mode 100644 index 0000000..6b6b5fc --- /dev/null +++ b/src/store/endpoints/dashboard-endpoints.js @@ -0,0 +1,45 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const dashboardEndpoints = (builder) => ({ + getDashboards: builder.query({ + query: (scenarioID) => `dashboards?scenarioID=${scenarioID}`, + }), + addDashboard: builder.mutation({ + query: (dashboard) => ({ + url: 'dashboards', + method: 'POST', + body: dashboard, + }), + }), + deleteDashboard: builder.mutation({ + query: (dashboardID) => ({ + url: `dashboards/${dashboardID}`, + method: 'DELETE', + }), + }), + updateDashboard: builder.mutation({ + query: ({ dashboardID, dashboard }) => ({ + url: `dashboards/${dashboardID}`, + method: 'PUT', + body: { dashboard }, + }), + }), + getDashboard: builder.query({ + query: (dashboardID) => `/dashboards/${dashboardID}`, + }), +}); diff --git a/src/store/endpoints/file-endpoints.js b/src/store/endpoints/file-endpoints.js new file mode 100644 index 0000000..7810b19 --- /dev/null +++ b/src/store/endpoints/file-endpoints.js @@ -0,0 +1,60 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const fileEndpoints = (builder) => ({ + getFiles: builder.query({ + query: (scenarioID) => ({ + url: 'files', + params: { scenarioID }, + }), + }), + addFile: builder.mutation({ + query: ({ scenarioID, file }) => { + const formData = new FormData(); + formData.append('inputFile', file); + return { + url: `files?scenarioID=${scenarioID}`, + method: 'POST', + body: formData, + }; + }, + }), + downloadFile: builder.query({ + query: (fileID) => ({ + url: `files/${fileID}`, + responseHandler: 'blob', + responseType: 'blob', + }), + }), + updateFile: builder.mutation({ + query: ({ fileID, file }) => { + const formData = new FormData(); + formData.append('inputFile', file); + return { + url: `files/${fileID}`, + method: 'PUT', + body: formData, + }; + }, + }), + deleteFile: builder.mutation({ + query: (fileID) => ({ + url: `files/${fileID}`, + method: 'DELETE', + }), + }), +}); diff --git a/src/store/endpoints/ic-endpoints.js b/src/store/endpoints/ic-endpoints.js new file mode 100644 index 0000000..fdb2f0a --- /dev/null +++ b/src/store/endpoints/ic-endpoints.js @@ -0,0 +1,29 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const icEndpoints = (builder) => ({ + getICS: builder.query({ + query: () => 'ic', + }), + sendAction: builder.mutation({ + query: (params) => ({ + url: `/ic/${params.icid}/action`, + method: 'POST', + body: [params], + }), + }), +}); diff --git a/src/store/endpoints/result-endpoints.js b/src/store/endpoints/result-endpoints.js new file mode 100644 index 0000000..b269cd9 --- /dev/null +++ b/src/store/endpoints/result-endpoints.js @@ -0,0 +1,38 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const resultEndpoints = (builder) => ({ + getResults: builder.query({ + query: (scenarioID) => ({ + url: 'results', + params: { scenarioID }, + }), + }), + addResult: builder.mutation({ + query: (result) => ({ + url: 'results', + method: 'POST', + body: result, + }), + }), + deleteResult: builder.mutation({ + query: (resultID) => ({ + url: `results/${resultID}`, + method: 'DELETE', + }), + }), +}); diff --git a/src/store/endpoints/scenario-endpoints.js b/src/store/endpoints/scenario-endpoints.js new file mode 100644 index 0000000..b3e036d --- /dev/null +++ b/src/store/endpoints/scenario-endpoints.js @@ -0,0 +1,60 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const scenarioEndpoints = (builder) => ({ + getScenarios: builder.query({ + query: () => 'scenarios', + }), + getScenarioById: builder.query({ + query: (id) => `scenarios/${id}`, + }), + addScenario: builder.mutation({ + query: (scenario) => ({ + url: 'scenarios', + method: 'POST', + body: scenario, + }), + }), + deleteScenario: builder.mutation({ + query: (id) => ({ + url: `scenarios/${id}`, + method: 'DELETE', + }), + }), + updateScenario: builder.mutation({ + query: ({ id, ...updatedScenario }) => ({ + url: `scenarios/${id}`, + method: 'PUT', + body: updatedScenario, + }), + }), + getUsersOfScenario: builder.query({ + query: (scenarioID) => `scenarios/${scenarioID}/users/`, + }), + addUserToScenario: builder.mutation({ + query: ({ scenarioID, username }) => ({ + url: `scenarios/${scenarioID}/user?username=${username}`, + method: 'PUT', + }), + }), + removeUserFromScenario: builder.mutation({ + query: ({ scenarioID, username }) => ({ + url: `scenarios/${scenarioID}/user/?username=${username}`, + method: 'DELETE', + }), + }), +}); diff --git a/src/store/endpoints/signal-endpoints.js b/src/store/endpoints/signal-endpoints.js new file mode 100644 index 0000000..544d969 --- /dev/null +++ b/src/store/endpoints/signal-endpoints.js @@ -0,0 +1,38 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const signalEndpoints = (builder) => ({ + getSignals: builder.query({ + query: ({ direction, configID }) => ({ + url: 'signals', + params: { direction, configID }, + }), + }), + addSignal: builder.mutation({ + query: (signal) => ({ + url: 'signals', + method: 'POST', + body: { signal }, + }), + }), + deleteSignal: builder.mutation({ + query: (signalID) => ({ + url: `signals/${signalID}`, + method: 'DELETE', + }), + }), +}); diff --git a/src/store/endpoints/user-endpoints.js b/src/store/endpoints/user-endpoints.js new file mode 100644 index 0000000..e958edd --- /dev/null +++ b/src/store/endpoints/user-endpoints.js @@ -0,0 +1,45 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const userEndpoints = (builder) => ({ + getUsers: builder.query({ + query: () => 'users', + }), + getUserById: builder.query({ + query: (id) => `users/${id}`, + }), + addUser: builder.mutation({ + query: (user) => ({ + url: 'users', + method: 'POST', + body: user, + }), + }), + updateUser: builder.mutation({ + query: (user) => ({ + url: `users/${user.id}`, + method: 'PUT', + body: { user }, + }), + }), + deleteUser: builder.mutation({ + query: (id) => ({ + url: `users/${id}`, + method: 'DELETE', + }), + }), +}); \ No newline at end of file diff --git a/src/store/endpoints/widget-endpoints.js b/src/store/endpoints/widget-endpoints.js new file mode 100644 index 0000000..9837ae4 --- /dev/null +++ b/src/store/endpoints/widget-endpoints.js @@ -0,0 +1,48 @@ +/** + * This file is part of VILLASweb. + * + * VILLASweb is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * VILLASweb is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with VILLASweb. If not, see . + ******************************************************************************/ + +export const widgetEndpoints = (builder) => ({ + getWidgets: builder.query({ + query: (dashboardID) => ({ + url: 'widgets', + params: { dashboardID }, + }), + }), + addWidget: builder.mutation({ + query: (widget) => ({ + url: 'widgets', + method: 'POST', + body: { widget }, + }), + }), + getWidget: builder.query({ + query: (widgetID) => `/widgets/${widgetID}`, + }), + updateWidget: builder.mutation({ + query: ({ widgetID, updatedWidget }) => ({ + url: `/widgets/${widgetID}`, + method: 'PUT', + body: updatedWidget, + }), + }), + deleteWidget: builder.mutation({ + query: (widgetID) => ({ + url: `/widgets/${widgetID}`, + method: 'DELETE', + }), + }), +}); \ No newline at end of file diff --git a/src/store/index.js b/src/store/index.js index c4f6072..46133f8 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -20,9 +20,11 @@ import userReducer from './userSlice'; import icReducer from './icSlice'; import configReducer from './configSlice' import { apiSlice } from "./apiSlice"; +import authReducer from './authSlice'; export const store = configureStore({ reducer: { + auth: authReducer, user: userReducer, infrastructure: icReducer, config: configReducer,