mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
added both redux versions
Signed-off-by: iripiri <ikoester@eonerc.rwth-aachen.de>
This commit is contained in:
parent
ab4b47721e
commit
5247019c56
23 changed files with 803 additions and 157 deletions
|
@ -122,6 +122,7 @@ class App extends React.Component {
|
|||
<Route exact path="/scenarios" component={Scenarios}/>
|
||||
<Route path="/scenarios/:scenario" component={Scenario} />
|
||||
<Route path="/dashboards/:dashboard" component={Dashboard} />
|
||||
<Route path="/dashboards-new/:dashboard" component={Dashboard} />
|
||||
</>
|
||||
: '' }
|
||||
{ currentUser.role === "Admin" || pages.infrastructure ? <>
|
||||
|
|
|
@ -15,29 +15,30 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import RestDataManager from './common/data-managers/rest-data-manager';
|
||||
import RestAPI from './common/api/rest-api';
|
||||
import AppDispatcher from './common/app-dispatcher';
|
||||
|
||||
import RestDataManager from "./common/data-managers/rest-data-manager";
|
||||
import RestAPI from "./common/api/rest-api";
|
||||
import AppDispatcher from "./common/app-dispatcher";
|
||||
|
||||
class ConfigReader extends RestDataManager {
|
||||
constructor() {
|
||||
super('config', '/config');
|
||||
super("config", "/config");
|
||||
}
|
||||
|
||||
loadConfig() {
|
||||
RestAPI.get(this.makeURL('/config'), null).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'config/loaded',
|
||||
data: response,
|
||||
RestAPI.get(this.makeURL("/config"), null)
|
||||
.then((response) => {
|
||||
AppDispatcher.dispatch({
|
||||
type: "config/loaded",
|
||||
data: response,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
AppDispatcher.dispatch({
|
||||
type: "config/load-error",
|
||||
error: error,
|
||||
});
|
||||
});
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'config/load-error',
|
||||
error: error,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default new ConfigReader();
|
||||
export default new ConfigReader();
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
import RestDataManager from '../common/data-managers/rest-data-manager';
|
||||
import AppDispatcher from "../common/app-dispatcher";
|
||||
|
||||
class DashboardsDataManager extends RestDataManager{
|
||||
class DashboardsDataManager extends RestDataManager {
|
||||
constructor() {
|
||||
super('dashboard', '/dashboards');
|
||||
this.onLoad = this.onDashboardsLoad
|
||||
|
|
20
src/index.js
20
src/index.js
|
@ -15,15 +15,21 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import Router from './router';
|
||||
import Router from "./router";
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import './styles/index.css';
|
||||
// Redux
|
||||
import { Provider } from "react-redux";
|
||||
import store from "./redux/store";
|
||||
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import "./styles/index.css";
|
||||
|
||||
ReactDOM.render(
|
||||
<Router />,
|
||||
document.getElementById('root')
|
||||
<Provider store={store}>
|
||||
<Router />
|
||||
</Provider>,
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
|
110
src/new_redux/slices/arraySlice.js
Normal file
110
src/new_redux/slices/arraySlice.js
Normal file
|
@ -0,0 +1,110 @@
|
|||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import AppDispatcher from "./app-dispatcher";
|
||||
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
|
||||
import NotificationsFactory from "./data-managers/notifications-factory";
|
||||
|
||||
const initialState = [];
|
||||
const arraySlice = createSlice({
|
||||
name: "array",
|
||||
initialState,
|
||||
reducers: {
|
||||
startLoad: (state, action) => {
|
||||
if (Array.isArray(action.payload.data)) {
|
||||
action.payload.data.forEach((id) => {
|
||||
// Load logic here using dataManager
|
||||
});
|
||||
} else {
|
||||
// Load logic here using dataManager
|
||||
}
|
||||
},
|
||||
loaded: (state, action) => {
|
||||
if (Array.isArray(action.payload.data)) {
|
||||
// Handle loaded data using updateElements
|
||||
} else {
|
||||
// Handle loaded data using updateElements
|
||||
}
|
||||
},
|
||||
loadError: (state, action) => {
|
||||
if (
|
||||
action.payload.error &&
|
||||
!action.payload.error.handled &&
|
||||
action.payload.error.response
|
||||
) {
|
||||
// Handle load error and add notification
|
||||
NotificationsDataManager.addNotification(
|
||||
NotificationsFactory.LOAD_ERROR(
|
||||
action.payload.error.response.body.message
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
startAdd: (state, action) => {
|
||||
// Add logic here using dataManager
|
||||
},
|
||||
added: (state, action) => {
|
||||
if (
|
||||
typeof action.payload.data.managedexternally !== "undefined" &&
|
||||
action.payload.data.managedexternally === true
|
||||
)
|
||||
return state;
|
||||
// Handle added data using updateElements
|
||||
},
|
||||
addError: (state, action) => {
|
||||
// Handle add error
|
||||
},
|
||||
startRemove: (state, action) => {
|
||||
// Remove logic here using dataManager
|
||||
},
|
||||
removed: (state, action) => {
|
||||
if (action.payload.original) {
|
||||
// Handle item removal using filter
|
||||
} else {
|
||||
// Handle item removal using filter
|
||||
}
|
||||
},
|
||||
removeError: (state, action) => {
|
||||
if (
|
||||
action.payload.error &&
|
||||
!action.payload.error.handled &&
|
||||
action.payload.error.response
|
||||
) {
|
||||
// Handle remove error and add notification
|
||||
NotificationsDataManager.addNotification(
|
||||
NotificationsFactory.DELETE_ERROR(
|
||||
action.payload.error.response.body.message
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
startEdit: (state, action) => {
|
||||
if (action.payload.id) {
|
||||
// Edit logic here using dataManager with an ID
|
||||
} else {
|
||||
// Edit logic here using dataManager without an ID
|
||||
}
|
||||
},
|
||||
edited: (state, action) => {
|
||||
// Handle edited data using updateElements
|
||||
},
|
||||
editError: (state, action) => {
|
||||
// Handle edit error
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
startLoad,
|
||||
loaded,
|
||||
loadError,
|
||||
startAdd,
|
||||
added,
|
||||
addError,
|
||||
startRemove,
|
||||
removed,
|
||||
removeError,
|
||||
startEdit,
|
||||
edited,
|
||||
editError,
|
||||
} = arraySlice.actions;
|
||||
|
||||
export default arraySlice.reducer;
|
28
src/new_redux/slices/counterSlice.js
Normal file
28
src/new_redux/slices/counterSlice.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { createSlice } from '@reduxjs/toolkit'
|
||||
|
||||
export const counterSlice = createSlice({
|
||||
name: 'counter',
|
||||
initialState: {
|
||||
value: 0
|
||||
},
|
||||
reducers: {
|
||||
increment: state => {
|
||||
// Redux Toolkit allows us to write "mutating" logic in reducers. It
|
||||
// doesn't actually mutate the state because it uses the Immer library,
|
||||
// which detects changes to a "draft state" and produces a brand new
|
||||
// immutable state based off those changes
|
||||
state.value += 1
|
||||
},
|
||||
decrement: state => {
|
||||
state.value -= 1
|
||||
},
|
||||
incrementByAmount: (state, action) => {
|
||||
state.value += action.payload
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { increment, decrement, incrementByAmount } = counterSlice.actions
|
||||
|
||||
export default counterSlice.reducer
|
131
src/new_redux/slices/icdataSlice.js
Normal file
131
src/new_redux/slices/icdataSlice.js
Normal file
|
@ -0,0 +1,131 @@
|
|||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import ICDataDataManager from "./ic-data-data-manager";
|
||||
|
||||
const MAX_VALUES = 10000;
|
||||
|
||||
const initialState = {};
|
||||
|
||||
const icDataSlice = createSlice({
|
||||
name: "icData",
|
||||
initialState,
|
||||
reducers: {
|
||||
opened: (state, action) => {
|
||||
// Create an entry for the infrastructure component
|
||||
if (state[action.payload.id] === undefined) {
|
||||
state[action.payload.id] = {};
|
||||
}
|
||||
},
|
||||
prepareSignalsIn: (state, action) => {
|
||||
if (state[action.payload.id] === undefined) {
|
||||
state[action.payload.id] = {};
|
||||
}
|
||||
state[action.payload.id].input = {
|
||||
sequence: -1,
|
||||
length: action.payload.length,
|
||||
version: 2,
|
||||
type: 0,
|
||||
timestamp: Date.now(),
|
||||
values: new Array(action.payload.length).fill(0),
|
||||
};
|
||||
},
|
||||
prepareSignalsOut: (state, action) => {
|
||||
if (state[action.payload.id] === undefined) {
|
||||
state[action.payload.id] = {};
|
||||
}
|
||||
state[action.payload.id].output = {
|
||||
sequence: -1,
|
||||
length: action.payload.length,
|
||||
values: [],
|
||||
};
|
||||
},
|
||||
dataChanged: (state, action) => {
|
||||
if (state[action.payload.id] == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state[action.payload.id].output == null) {
|
||||
state[action.payload.id].output = {
|
||||
values: [],
|
||||
};
|
||||
}
|
||||
|
||||
for (let j = 0; j < action.payload.data.length; j++) {
|
||||
let smp = action.payload.data[j];
|
||||
|
||||
if (smp.source_index !== 0) {
|
||||
for (let i = 0; i < smp.length; i++) {
|
||||
while (state[action.payload.id].input.values.length < i + 1) {
|
||||
state[action.payload.id].input.values.push([]);
|
||||
}
|
||||
|
||||
state[action.payload.id].input.values[i] = smp.values[i];
|
||||
|
||||
if (state[action.payload.id].input.values[i].length > MAX_VALUES) {
|
||||
const pos =
|
||||
state[action.payload.id].input.values[i].length - MAX_VALUES;
|
||||
state[action.payload.id].input.values[i].splice(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
state[action.payload.id].input.timestamp = smp.timestamp;
|
||||
state[action.payload.id].input.sequence = smp.sequence;
|
||||
|
||||
// Trigger updates of widgets that use this signal
|
||||
ICDataDataManager.updateSignalValueInWidgets(
|
||||
smp.source_index,
|
||||
smp.values
|
||||
);
|
||||
} else {
|
||||
for (let i = 0; i < smp.length; i++) {
|
||||
while (state[action.payload.id].output.values.length < i + 1) {
|
||||
state[action.payload.id].output.values.push([]);
|
||||
}
|
||||
|
||||
state[action.payload.id].output.values[i].push({
|
||||
x: smp.timestamp,
|
||||
y: smp.values[i],
|
||||
});
|
||||
|
||||
if (state[action.payload.id].output.values[i].length > MAX_VALUES) {
|
||||
const pos =
|
||||
state[action.payload.id].output.values[i].length - MAX_VALUES;
|
||||
state[action.payload.id].output.values[i].splice(0, pos);
|
||||
}
|
||||
|
||||
state[action.payload.id].output.timestamp = smp.timestamp;
|
||||
state[action.payload.id].output.sequence = smp.sequence;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
inputChanged: (state, action) => {
|
||||
if (
|
||||
state[action.payload.ic] == null ||
|
||||
state[action.payload.ic].input == null
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
state[action.payload.ic].input.timestamp = Date.now();
|
||||
state[action.payload.ic].input.sequence++;
|
||||
state[action.payload.ic].input.values[action.payload.signalIndex] =
|
||||
action.payload.data;
|
||||
state[action.payload.ic].input.length =
|
||||
state[action.payload.ic].input.values.length;
|
||||
state[action.payload.ic].input.source_index = action.payload.signalID;
|
||||
|
||||
let input = JSON.parse(JSON.stringify(state[action.payload.ic].input));
|
||||
ICDataDataManager.send(input, action.payload.ic);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
opened,
|
||||
prepareSignalsIn,
|
||||
prepareSignalsOut,
|
||||
dataChanged,
|
||||
inputChanged,
|
||||
} = icDataSlice.actions;
|
||||
|
||||
export default icDataSlice.reducer;
|
59
src/new_redux/slices/loginSlice.js
Normal file
59
src/new_redux/slices/loginSlice.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import ICDataDataManager from "../../user/users-data-manager";
|
||||
|
||||
const initialState = {
|
||||
currentUser: null,
|
||||
token: null,
|
||||
loginMessage: null,
|
||||
config: null,
|
||||
};
|
||||
|
||||
const loginSlice = createSlice({
|
||||
name: "login",
|
||||
initialState,
|
||||
reducers: {
|
||||
config_loaded: (state, action) => {
|
||||
state.config = action.payload;
|
||||
},
|
||||
config_load_error: (state, action) => {
|
||||
state.config = null;
|
||||
},
|
||||
users_login: (state, action) => {
|
||||
UsersDataManager.login(action.payload.username, action.payload.password);
|
||||
state.loginMessage = null;
|
||||
},
|
||||
users_extlogin: (state, action) => {
|
||||
UsersDataManager.login();
|
||||
state.loginMessage = null;
|
||||
},
|
||||
users_logout: (state, action) => {
|
||||
ICDataDataManager.closeAll();
|
||||
localStorage.clear();
|
||||
state.token = null;
|
||||
state.currentUser = null;
|
||||
state.loginMessage = null;
|
||||
},
|
||||
users_logged_in: (state, action) => {
|
||||
state.token = action.payload.token;
|
||||
state.currentUser = action.payload.currentUser;
|
||||
},
|
||||
users_login_error: (state, action) => {
|
||||
if (action.payload.error && !action.payload.error.handled) {
|
||||
state.loginMessage = "Wrong credentials! Please try again.";
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const {
|
||||
config_loaded,
|
||||
config_load_error,
|
||||
users_logged_in,
|
||||
users_login_error,
|
||||
users_login,
|
||||
users_extlogin,
|
||||
users_logout,
|
||||
} = loginSlice.actions;
|
||||
|
||||
export default loginSlice.reducer;
|
33
src/new_redux/slices/resultSlice.js
Normal file
33
src/new_redux/slices/resultSlice.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import { createSlice } from '@reduxjs/toolkit';
|
||||
import { arraySlice } from './arrayReducer';
|
||||
// Import any other necessary utilities
|
||||
|
||||
export const resultSlice = createSlice({
|
||||
name: 'results',
|
||||
initialState: arraySlice.getInitialState(),
|
||||
reducers: {
|
||||
loaded: (state, action) => {
|
||||
// Use your simplifyTimestamps function here before deferring to the arraySlice reducer
|
||||
arraySlice.caseReducers.loaded(state, action);
|
||||
},
|
||||
added: (state, action) => {
|
||||
// Similar changes go here
|
||||
arraySlice.caseReducers.added(state, action);
|
||||
},
|
||||
edited: (state, action) => {
|
||||
// Repeat the process for the 'edited' logic
|
||||
arraySlice.caseReducers.edited(state, action);
|
||||
},
|
||||
removed: (state, action) => {
|
||||
// Implement additional logic if needed and then do the same
|
||||
arraySlice.caseReducers.removed(state, action);
|
||||
},
|
||||
// Add additional case reducers here
|
||||
},
|
||||
});
|
||||
|
||||
// Export actions
|
||||
export const { loaded, added, edited, removed } = resultSlice.actions;
|
||||
|
||||
// Export the reducer
|
||||
export default resultSlice.reducer;
|
28
src/new_redux/slices/urlSlice.js
Normal file
28
src/new_redux/slices/urlSlice.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import { createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
const urlParamsString = localStorage.getItem("urlParams");
|
||||
const urlParams =
|
||||
urlParamsString !== null ? JSON.parse(urlParamsString) : [];
|
||||
|
||||
const setUrlFunction = (urlParams) => {
|
||||
localStorage.setItem("urlParams", JSON.stringify(urlParams));
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
urlParams: urlParams,
|
||||
};
|
||||
|
||||
export const urlSlice = createSlice({
|
||||
name: "urlslice",
|
||||
initialState,
|
||||
reducers: {
|
||||
setUrlParams: (state, action) => {
|
||||
state.urlParams = action.payload.urlParams;
|
||||
setUrlFunction(action.payload.urlParams);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setUrlParams } = urlSlice.actions;
|
||||
|
||||
export default urlSlice.reducer;
|
10
src/new_redux/store.js
Normal file
10
src/new_redux/store.js
Normal file
|
@ -0,0 +1,10 @@
|
|||
import { configureStore } from "@reduxjs/toolkit";
|
||||
import loginReducer from "./slices/loginSlice";
|
||||
import counterReducer from "./slices/counterSlice";
|
||||
|
||||
export default configureStore({
|
||||
reducer: {
|
||||
login: loginReducer,
|
||||
counter: counterReducer,
|
||||
},
|
||||
});
|
3
src/redux/actionTypes.js
Normal file
3
src/redux/actionTypes.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
export const ADD_TODO = "ADD_TODO";
|
||||
export const TOGGLE_TODO = "TOGGLE_TODO";
|
||||
export const SET_FILTER = "SET_FILTER";
|
18
src/redux/actions.js
Normal file
18
src/redux/actions.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import { ADD_TODO, TOGGLE_TODO, SET_FILTER } from "./actionTypes";
|
||||
|
||||
let nextTodoId = 0;
|
||||
|
||||
export const addTodo = content => ({
|
||||
type: ADD_TODO,
|
||||
payload: {
|
||||
id: ++nextTodoId,
|
||||
content
|
||||
}
|
||||
});
|
||||
|
||||
export const toggleTodo = id => ({
|
||||
type: TOGGLE_TODO,
|
||||
payload: { id }
|
||||
});
|
||||
|
||||
export const setFilter = filter => ({ type: SET_FILTER, payload: { filter } });
|
5
src/redux/actions/index.js
Normal file
5
src/redux/actions/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
const loAction = () => ({
|
||||
type: "login",
|
||||
});
|
||||
|
||||
export { loAction };
|
5
src/redux/reducers/index.js
Normal file
5
src/redux/reducers/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { combineReducers } from "redux";
|
||||
|
||||
import todos from "./todos";
|
||||
|
||||
export default combineReducers({ todos });
|
33
src/redux/reducers/login.js
Normal file
33
src/redux/reducers/login.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
const initialState = {
|
||||
currentUser: null,
|
||||
token: null,
|
||||
loginMessage: null,
|
||||
config: null,
|
||||
};
|
||||
|
||||
const loginReducer = (state = initialState, action) => {
|
||||
switch (action.type) {
|
||||
case "config_loaded":
|
||||
return { ...state, config: action.payload };
|
||||
case "config_load_error":
|
||||
return { ...state, config: null };
|
||||
case "users_logged_in":
|
||||
return {
|
||||
...state,
|
||||
token: action.payload.token,
|
||||
currentUser: action.payload.currentUser,
|
||||
};
|
||||
case "users_login_error":
|
||||
if (action.payload.error && !action.payload.error.handled) {
|
||||
return {
|
||||
...state,
|
||||
loginMessage: "Wrong credentials! Please try again.",
|
||||
};
|
||||
}
|
||||
return state;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default loginReducer;
|
40
src/redux/reducers/todos.js
Normal file
40
src/redux/reducers/todos.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
import { ADD_TODO, TOGGLE_TODO } from "../actionTypes";
|
||||
|
||||
const initialState = {
|
||||
allIds: [],
|
||||
byIds: {},
|
||||
};
|
||||
|
||||
export default function (state = initialState, action) {
|
||||
switch (action.type) {
|
||||
case ADD_TODO: {
|
||||
const { id, content } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
allIds: [...state.allIds, id],
|
||||
byIds: {
|
||||
...state.byIds,
|
||||
[id]: {
|
||||
content,
|
||||
completed: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
case TOGGLE_TODO: {
|
||||
const { id } = action.payload;
|
||||
return {
|
||||
...state,
|
||||
byIds: {
|
||||
...state.byIds,
|
||||
[id]: {
|
||||
...state.byIds[id],
|
||||
completed: !state.byIds[id].completed,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
14
src/redux/selectors.js
Normal file
14
src/redux/selectors.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
export const getTodosState = (store) => store.todos;
|
||||
|
||||
export const getTodoList = (store) =>
|
||||
getTodosState(store) ? getTodosState(store).allIds : [];
|
||||
|
||||
export const getTodoById = (store, id) =>
|
||||
getTodosState(store) ? { ...getTodosState(store).byIds[id], id } : {};
|
||||
|
||||
/**
|
||||
* example of a slightly more complex selector
|
||||
* select from store combining information from multiple reducers
|
||||
*/
|
||||
export const getTodos = (store) =>
|
||||
getTodoList(store).map((id) => getTodoById(store, id));
|
4
src/redux/store.js
Normal file
4
src/redux/store.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
import { createStore } from "redux";
|
||||
import rootReducer from "./reducers";
|
||||
|
||||
export default createStore(rootReducer);
|
|
@ -15,24 +15,26 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React from 'react';
|
||||
import { BrowserRouter, Route, Switch } from 'react-router-dom';
|
||||
import App from './app';
|
||||
import Login from './user/login';
|
||||
import Logout from './user/logout';
|
||||
import LoginComplete from './user/login-complete'
|
||||
import React from "react";
|
||||
import { BrowserRouter, Route, Switch } from "react-router-dom";
|
||||
import App from "./app";
|
||||
import Login from "./user/login";
|
||||
import Logout from "./user/logout";
|
||||
import LoginComplete from "./user/login-complete";
|
||||
|
||||
class Root extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route path='/login/complete' component={LoginComplete} />
|
||||
<Route path='/login' component={Login} />
|
||||
<Route path='/logout' component={Logout} />
|
||||
<Route path='/' component={App} />
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
|
||||
<BrowserRouter>
|
||||
<Switch>
|
||||
<Route path="/login/complete" component={LoginComplete} />
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/logout" component={Logout} />
|
||||
<Route path="/" component={App} />
|
||||
</Switch>
|
||||
</BrowserRouter>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,9 @@ import EditFilesDialog from '../file/edit-files'
|
|||
import ScenarioUsersTable from "./scenario-users-table";
|
||||
|
||||
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { decrement, increment } from "../new_redux/slices/counterSlice";
|
||||
|
||||
class Scenario extends React.Component {
|
||||
|
||||
constructor(props) {
|
||||
|
@ -49,6 +52,8 @@ class Scenario extends React.Component {
|
|||
this.state = {
|
||||
filesEditModal: false,
|
||||
filesEditSaveState: [],
|
||||
// count: useSelector((state) => state.counter.value),
|
||||
// dispatch: useDispatch(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,33 +15,61 @@
|
|||
* along with VILLASweb. If not, see <http://www.gnu.org/licenses/>.
|
||||
******************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { Container } from 'flux/utils';
|
||||
import FileSaver from 'file-saver';
|
||||
import AppDispatcher from '../common/app-dispatcher';
|
||||
import ScenarioStore from './scenario-store';
|
||||
import DashboardStore from '../dashboard/dashboard-store';
|
||||
import React, { Component } from "react";
|
||||
import { Container } from "flux/utils";
|
||||
import FileSaver from "file-saver";
|
||||
import AppDispatcher from "../common/app-dispatcher";
|
||||
import ScenarioStore from "./scenario-store";
|
||||
import DashboardStore from "../dashboard/dashboard-store";
|
||||
import WidgetStore from "../widget/widget-store";
|
||||
import ComponentConfigStore from '../componentconfig/config-store';
|
||||
import SignalStore from '../signal/signal-store'
|
||||
import ResultStore from '../result/result-store'
|
||||
import FileStore from '../file/file-store'
|
||||
import LoginStore from '../user/login-store'
|
||||
import UsersStore from '../user/users-store'
|
||||
import ICStore from '../ic/ic-store'
|
||||
import ICDataStore from '../ic/ic-data-store'
|
||||
import { Table, ButtonColumn, DataColumn, LinkColumn } from '../common/table';
|
||||
import NewScenarioDialog from './new-scenario';
|
||||
import EditScenarioDialog from './edit-scenario';
|
||||
import ImportScenarioDialog from './import-scenario';
|
||||
import DeleteDialog from '../common/dialogs/delete-dialog';
|
||||
import IconButton from '../common/buttons/icon-button';
|
||||
import ComponentConfigStore from "../componentconfig/config-store";
|
||||
import SignalStore from "../signal/signal-store";
|
||||
import ResultStore from "../result/result-store";
|
||||
import FileStore from "../file/file-store";
|
||||
import LoginStore from "../user/login-store";
|
||||
import UsersStore from "../user/users-store";
|
||||
import ICStore from "../ic/ic-store";
|
||||
import ICDataStore from "../ic/ic-data-store";
|
||||
import { Table, ButtonColumn, DataColumn, LinkColumn } from "../common/table";
|
||||
import NewScenarioDialog from "./new-scenario";
|
||||
import EditScenarioDialog from "./edit-scenario";
|
||||
import ImportScenarioDialog from "./import-scenario";
|
||||
import DeleteDialog from "../common/dialogs/delete-dialog";
|
||||
import IconButton from "../common/buttons/icon-button";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { addTodo } from "../redux/actions";
|
||||
import { getTodos } from "../redux/selectors";
|
||||
|
||||
class Scenarios extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { input: "" };
|
||||
}
|
||||
|
||||
updateInput = (input) => {
|
||||
this.setState({ input });
|
||||
};
|
||||
|
||||
handleAddTodo = () => {
|
||||
this.props.addTodo(this.state.input);
|
||||
this.setState({ input: "" });
|
||||
};
|
||||
|
||||
static getStores() {
|
||||
return [ScenarioStore, DashboardStore, WidgetStore, ComponentConfigStore, SignalStore, ResultStore, FileStore,LoginStore, UsersStore, ICStore, ICDataStore];
|
||||
return [
|
||||
ScenarioStore,
|
||||
DashboardStore,
|
||||
WidgetStore,
|
||||
ComponentConfigStore,
|
||||
SignalStore,
|
||||
ResultStore,
|
||||
FileStore,
|
||||
LoginStore,
|
||||
UsersStore,
|
||||
ICStore,
|
||||
ICDataStore,
|
||||
];
|
||||
}
|
||||
|
||||
static calculateState(prevState, props) {
|
||||
|
@ -62,21 +90,21 @@ class Scenarios extends Component {
|
|||
importModal: false,
|
||||
modalScenario: {},
|
||||
selectedScenarios: prevState.selectedScenarios || [],
|
||||
currentUser: JSON.parse(localStorage.getItem("currentUser"))
|
||||
currentUser: JSON.parse(localStorage.getItem("currentUser")),
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-load',
|
||||
token: this.state.sessionToken
|
||||
type: "scenarios/start-load",
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
|
||||
closeNewModal(data) {
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-add',
|
||||
type: "scenarios/start-add",
|
||||
data: data,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
|
@ -107,28 +135,28 @@ class Scenarios extends Component {
|
|||
this.state.dashboards.forEach((dashboard) => {
|
||||
if (dashboard.id === this.state.modalScenario.id) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'dashboards/start-remove',
|
||||
type: "dashboards/start-remove",
|
||||
data: dashboard,
|
||||
token: this.state.sessionToken
|
||||
})
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-remove',
|
||||
type: "scenarios/start-remove",
|
||||
data: this.state.modalScenario,
|
||||
token: this.state.sessionToken
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
closeEditModal(data) {
|
||||
this.setState({ editModal: false });
|
||||
|
||||
if (data != null) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-edit',
|
||||
type: "scenarios/start-edit",
|
||||
data,
|
||||
token: this.state.sessionToken
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +166,7 @@ class Scenarios extends Component {
|
|||
|
||||
if (data) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-add',
|
||||
type: "scenarios/start-add",
|
||||
data: data,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
|
@ -146,7 +174,7 @@ class Scenarios extends Component {
|
|||
}
|
||||
|
||||
onModalKeyPress = (event) => {
|
||||
if (event.key === 'Enter') {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
|
||||
this.confirmDeleteModal();
|
||||
|
@ -154,17 +182,27 @@ class Scenarios extends Component {
|
|||
};
|
||||
|
||||
getConfigs(scenarioID) {
|
||||
let configs = JSON.parse(JSON.stringify(this.state.configs.filter(config => config.scenarioID === scenarioID)));
|
||||
let configs = JSON.parse(
|
||||
JSON.stringify(
|
||||
this.state.configs.filter((config) => config.scenarioID === scenarioID)
|
||||
)
|
||||
);
|
||||
configs.forEach((config) => {
|
||||
let signals = JSON.parse(JSON.stringify(SignalStore.getState().filter(s => s.configID === parseInt(config.id, 10))));
|
||||
let signals = JSON.parse(
|
||||
JSON.stringify(
|
||||
SignalStore.getState().filter(
|
||||
(s) => s.configID === parseInt(config.id, 10)
|
||||
)
|
||||
)
|
||||
);
|
||||
signals.forEach((signal) => {
|
||||
delete signal.configID;
|
||||
delete signal.id;
|
||||
})
|
||||
});
|
||||
|
||||
// two separate lists for inputMapping and outputMapping
|
||||
let inputSignals = signals.filter(s => s.direction === 'in');
|
||||
let outputSignals = signals.filter(s => s.direction === 'out');
|
||||
let inputSignals = signals.filter((s) => s.direction === "in");
|
||||
let outputSignals = signals.filter((s) => s.direction === "out");
|
||||
|
||||
// add signal mappings to config
|
||||
config["inputMapping"] = inputSignals;
|
||||
|
@ -172,20 +210,30 @@ class Scenarios extends Component {
|
|||
|
||||
delete config.id;
|
||||
delete config.scenarioID;
|
||||
})
|
||||
});
|
||||
|
||||
return configs;
|
||||
}
|
||||
|
||||
getDashboards(scenarioID) {
|
||||
let dashboards = JSON.parse(JSON.stringify(this.state.dashboards.filter(dashb => dashb.scenarioID === scenarioID)));
|
||||
let dashboards = JSON.parse(
|
||||
JSON.stringify(
|
||||
this.state.dashboards.filter((dashb) => dashb.scenarioID === scenarioID)
|
||||
)
|
||||
);
|
||||
// add Dashboards and Widgets to JSON object
|
||||
dashboards.forEach((dboard) => {
|
||||
let widgets = JSON.parse(JSON.stringify(WidgetStore.getState().filter(w => w.dashboardID === parseInt(dboard.id, 10))));
|
||||
let widgets = JSON.parse(
|
||||
JSON.stringify(
|
||||
WidgetStore.getState().filter(
|
||||
(w) => w.dashboardID === parseInt(dboard.id, 10)
|
||||
)
|
||||
)
|
||||
);
|
||||
widgets.forEach((widget) => {
|
||||
delete widget.dashboardID;
|
||||
delete widget.id;
|
||||
})
|
||||
});
|
||||
dboard["widgets"] = widgets;
|
||||
delete dboard.scenarioID;
|
||||
delete dboard.id;
|
||||
|
@ -205,13 +253,15 @@ class Scenarios extends Component {
|
|||
jsonObj["dashboards"] = this.getDashboards(scenarioID);
|
||||
|
||||
// create JSON string and show save dialog
|
||||
const blob = new Blob([JSON.stringify(jsonObj, null, 2)], { type: 'application/json' });
|
||||
FileSaver.saveAs(blob, 'scenario - ' + scenario.name + '.json');
|
||||
const blob = new Blob([JSON.stringify(jsonObj, null, 2)], {
|
||||
type: "application/json",
|
||||
});
|
||||
FileSaver.saveAs(blob, "scenario - " + scenario.name + ".json");
|
||||
}
|
||||
|
||||
duplicateScenario(index) {
|
||||
let scenario = JSON.parse(JSON.stringify(this.state.scenarios[index]));
|
||||
scenario.name = scenario.name + '_copy';
|
||||
scenario.name = scenario.name + "_copy";
|
||||
let jsonObj = scenario;
|
||||
|
||||
jsonObj["configs"] = this.getConfigs(scenario.id);
|
||||
|
@ -219,7 +269,7 @@ class Scenarios extends Component {
|
|||
|
||||
if (jsonObj) {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-add',
|
||||
type: "scenarios/start-add",
|
||||
data: jsonObj,
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
|
@ -236,92 +286,152 @@ class Scenarios extends Component {
|
|||
data.isLocked = !this.state.scenarios[index].isLocked;
|
||||
|
||||
AppDispatcher.dispatch({
|
||||
type: 'scenarios/start-edit',
|
||||
type: "scenarios/start-edit",
|
||||
data,
|
||||
token: this.state.sessionToken
|
||||
token: this.state.sessionToken,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const buttonStyle = {
|
||||
marginLeft: '10px',
|
||||
}
|
||||
marginLeft: "10px",
|
||||
};
|
||||
|
||||
const iconStyle = {
|
||||
height: '30px',
|
||||
width: '30px'
|
||||
}
|
||||
height: "30px",
|
||||
width: "30px",
|
||||
};
|
||||
|
||||
const { todos } = this.props;
|
||||
|
||||
return (
|
||||
<div className='section'>
|
||||
<h1>Scenarios
|
||||
<span className='icon-button'>
|
||||
<IconButton
|
||||
childKey={0}
|
||||
tooltip='Add Scenario'
|
||||
onClick={() => this.setState({ newModal: true })}
|
||||
icon='plus'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
<div className="section">
|
||||
<div>
|
||||
<input
|
||||
onChange={(e) => this.updateInput(e.target.value)}
|
||||
value={this.state.input}
|
||||
/>
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip='Import Scenario'
|
||||
onClick={() => this.setState({ importModal: true })}
|
||||
icon='upload'
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
<button className="add-todo" onClick={this.handleAddTodo}>
|
||||
Add Todo
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<ul>
|
||||
{todos.map((todo, index) => (
|
||||
<li key={index}>{todo.content}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<Table data={this.state.scenarios}>
|
||||
{this.state.currentUser.role === "Admin" ?
|
||||
<DataColumn
|
||||
title='ID'
|
||||
dataKey='id'
|
||||
<h1>
|
||||
Scenarios
|
||||
<span className="icon-button">
|
||||
<IconButton
|
||||
childKey={0}
|
||||
tooltip="Add Scenario"
|
||||
onClick={() => this.setState({ newModal: true })}
|
||||
icon="plus"
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
<IconButton
|
||||
childKey={1}
|
||||
tooltip="Import Scenario"
|
||||
onClick={() => this.setState({ importModal: true })}
|
||||
icon="upload"
|
||||
buttonStyle={buttonStyle}
|
||||
iconStyle={iconStyle}
|
||||
/>
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<Table data={this.state.scenarios}>
|
||||
{this.state.currentUser.role === "Admin" ? (
|
||||
<DataColumn title="ID" dataKey="id" />
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<LinkColumn
|
||||
title="Name"
|
||||
dataKey="name"
|
||||
link="/scenarios/"
|
||||
linkKey="id"
|
||||
/>
|
||||
: <></>
|
||||
}
|
||||
<LinkColumn
|
||||
title='Name'
|
||||
dataKey='name'
|
||||
link='/scenarios/'
|
||||
linkKey='id'
|
||||
/>
|
||||
{this.state.currentUser.role === "Admin" ?
|
||||
{this.state.currentUser.role === "Admin" ? (
|
||||
<ButtonColumn
|
||||
title="Locked"
|
||||
lockButton
|
||||
onChangeLock={(index, event) => this.onLock(index)}
|
||||
isLocked={(index) => this.isLocked(index)}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
<ButtonColumn
|
||||
title='Locked'
|
||||
lockButton
|
||||
onChangeLock={(index, event) => this.onLock(index)}
|
||||
isLocked={index => this.isLocked(index)}
|
||||
width="200"
|
||||
align="right"
|
||||
editButton
|
||||
deleteButton
|
||||
exportButton
|
||||
duplicateButton
|
||||
onEdit={(index) =>
|
||||
this.setState({
|
||||
editModal: true,
|
||||
modalScenario: this.state.scenarios[index],
|
||||
})
|
||||
}
|
||||
onDelete={(index) =>
|
||||
this.setState({
|
||||
deleteModal: true,
|
||||
modalScenario: this.state.scenarios[index],
|
||||
})
|
||||
}
|
||||
onExport={(index) => this.exportScenario(index)}
|
||||
onDuplicate={(index) => this.duplicateScenario(index)}
|
||||
isLocked={(index) => this.isLocked(index)}
|
||||
/>
|
||||
: <></>
|
||||
}
|
||||
<ButtonColumn
|
||||
width='200'
|
||||
align='right'
|
||||
editButton
|
||||
deleteButton
|
||||
exportButton
|
||||
duplicateButton
|
||||
onEdit={index => this.setState({ editModal: true, modalScenario: this.state.scenarios[index] })}
|
||||
onDelete={index => this.setState({ deleteModal: true, modalScenario: this.state.scenarios[index] })}
|
||||
onExport={index => this.exportScenario(index)}
|
||||
onDuplicate={index => this.duplicateScenario(index)}
|
||||
isLocked={index => this.isLocked(index)}
|
||||
</Table>
|
||||
|
||||
<NewScenarioDialog
|
||||
show={this.state.newModal}
|
||||
onClose={(data) => this.closeNewModal(data)}
|
||||
/>
|
||||
<EditScenarioDialog
|
||||
show={this.state.editModal}
|
||||
onClose={(data) => this.closeEditModal(data)}
|
||||
scenario={this.state.modalScenario}
|
||||
/>
|
||||
<ImportScenarioDialog
|
||||
show={this.state.importModal}
|
||||
onClose={(data) => this.closeImportModal(data)}
|
||||
nodes={this.state.nodes}
|
||||
/>
|
||||
</Table>
|
||||
|
||||
<NewScenarioDialog show={this.state.newModal} onClose={(data) => this.closeNewModal(data)} />
|
||||
<EditScenarioDialog show={this.state.editModal} onClose={(data) => this.closeEditModal(data)} scenario={this.state.modalScenario} />
|
||||
<ImportScenarioDialog show={this.state.importModal} onClose={data => this.closeImportModal(data)} nodes={this.state.nodes} />
|
||||
|
||||
<DeleteDialog title="scenario" name={this.state.modalScenario.name} show={this.state.deleteModal} onClose={(e) => this.closeDeleteModal(e)} />
|
||||
</div>
|
||||
);
|
||||
<DeleteDialog
|
||||
title="scenario"
|
||||
name={this.state.modalScenario.name}
|
||||
show={this.state.deleteModal}
|
||||
onClose={(e) => this.closeDeleteModal(e)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let fluxContainerConverter = require('../common/FluxContainerConverter');
|
||||
export default Container.create(fluxContainerConverter.convert(Scenarios));
|
||||
let fluxContainerConverter = require("../common/FluxContainerConverter");
|
||||
// export default Container.create(fluxContainerConverter.convert(Scenarios));
|
||||
|
||||
const mapStateToProps = (state) => ({
|
||||
todos: getTodos(state), // Assuming you have a selector called getTodos
|
||||
});
|
||||
|
||||
// Map the actions to the component's props
|
||||
const mapDispatchToProps = {
|
||||
addTodo,
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Container.create(fluxContainerConverter.convert(Scenarios)));
|
||||
|
|
|
@ -20,7 +20,7 @@ import SignalsDataManager from './signals-data-manager'
|
|||
import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
|
||||
import NotificationsFactory from "../common/data-managers/notifications-factory";
|
||||
|
||||
class SignalStore extends ArrayStore{
|
||||
class SignalStore extends ArrayStore{
|
||||
constructor() {
|
||||
super('signals', SignalsDataManager);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue