1
0
Fork 0
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:
Amir Nakhaei 2023-11-24 04:09:34 +01:00 committed by al3xa23
parent ab4b47721e
commit 5247019c56
23 changed files with 803 additions and 157 deletions

View file

@ -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 ? <>

View file

@ -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();

View file

@ -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

View file

@ -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")
);

View 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;

View 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

View 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;

View 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;

View 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;

View 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
View 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
View 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
View 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 } });

View file

@ -0,0 +1,5 @@
const loAction = () => ({
type: "login",
});
export { loAction };

View file

@ -0,0 +1,5 @@
import { combineReducers } from "redux";
import todos from "./todos";
export default combineReducers({ todos });

View 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;

View 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
View 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
View file

@ -0,0 +1,4 @@
import { createStore } from "redux";
import rootReducer from "./reducers";
export default createStore(rootReducer);

View file

@ -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>
);
}
}

View file

@ -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(),
}
}

View file

@ -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)));

View file

@ -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);
}