+ :
{
cell.map((element, elementIndex) =>
{element}
)
}
- }
+ }
})
}
diff --git a/src/componentconfig/config-table.js b/src/componentconfig/config-table.js
new file mode 100644
index 0000000..665850e
--- /dev/null
+++ b/src/componentconfig/config-table.js
@@ -0,0 +1,462 @@
+/**
+ * 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 React, {Component} from "react";
+import FileSaver from 'file-saver';
+import IconButton from "../common/icon-button";
+import Table from "../common/table";
+import TableColumn from "../common/table-column";
+import DeleteDialog from "../common/dialogs/delete-dialog";
+import AppDispatcher from "../common/app-dispatcher";
+import NotificationsDataManager from "../common/data-managers/notifications-data-manager";
+import ICAction from "../ic/ic-action";
+import EditConfigDialog from "./edit-config";
+import ImportConfigDialog from "./import-config";
+import EditSignalMappingDialog from "../signal/edit-signal-mapping";
+
+class ConfigTable extends Component {
+
+ constructor() {
+ super();
+
+ this.state = {
+ editConfigModal: false,
+ modalConfigData: {},
+ modalConfigIndex: 0,
+ deleteConfigModal: false,
+ importConfigModal: false,
+ newConfig: false,
+ selectedConfigs: [],
+ ExternalICInUse: false,
+ editOutputSignalsModal: false,
+ editInputSignalsModal: false,
+ }
+ }
+
+ static getDerivedStateFromProps(props, state){
+
+ let ExternalICInUse = false
+
+ for (let config of props.configs){
+ for (let component of props.ics) {
+ if ((config.icID === component.id) && (component.managedexternally === true)) {
+ ExternalICInUse = true;
+ break;
+ }
+ }
+ }
+
+ return {
+ ExternalICInUse: ExternalICInUse
+ };
+ }
+
+ addConfig() {
+ const config = {
+ scenarioID: this.props.scenario.id,
+ name: 'New Component Configuration',
+ icID: this.props.ics.length > 0 ? this.props.ics[0].id : null,
+ startParameters: {},
+ };
+
+ AppDispatcher.dispatch({
+ type: 'configs/start-add',
+ data: config,
+ token: this.props.sessionToken
+ });
+
+ this.setState({ newConfig: true });
+
+ }
+
+ closeEditConfigModal(data) {
+ this.setState({ editConfigModal: false, newConfig: false });
+
+ if (data) {
+ AppDispatcher.dispatch({
+ type: 'configs/start-edit',
+ data: data,
+ token: this.props.sessionToken,
+ });
+ }
+ }
+
+ closeDeleteConfigModal(confirmDelete) {
+ this.setState({ deleteConfigModal: false });
+
+ if (confirmDelete === false) {
+ return;
+ }
+
+ AppDispatcher.dispatch({
+ type: 'configs/start-remove',
+ data: this.state.modalConfigData,
+ token: this.props.sessionToken
+ });
+ }
+
+ importConfig(data) {
+ this.setState({ importConfigModal: false });
+
+ if (data == null) {
+ return;
+ }
+
+ let newConfig = JSON.parse(JSON.stringify(data.config))
+
+ newConfig["scenarioID"] = this.props.scenario.id;
+ newConfig.name = data.name;
+
+ AppDispatcher.dispatch({
+ type: 'configs/start-add',
+ data: newConfig,
+ token: this.props.sessionToken
+ });
+ }
+
+ copyConfig(index) {
+ let config = JSON.parse(JSON.stringify(this.props.configs[index]));
+
+ let signals = JSON.parse(JSON.stringify(this.props.signals.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');
+
+ // add signal mappings to config
+ config["inputMapping"] = inputSignals;
+ config["outputMapping"] = outputSignals;
+
+ delete config.id;
+ delete config.scenarioID;
+ delete config.inputLength;
+ delete config.outputLength;
+
+ return config;
+ }
+
+ exportConfig(index) {
+ let config = this.copyConfig(index);
+
+ // show save dialog
+ const blob = new Blob([JSON.stringify(config, null, 2)], { type: 'application/json' });
+ FileSaver.saveAs(blob, 'config-' + config.name + '.json');
+ }
+
+ duplicateConfig(index) {
+ let newConfig = this.copyConfig(index);
+ newConfig["scenarioID"] = this.props.scenario.id;
+ newConfig.name = newConfig.name + '_copy';
+
+ AppDispatcher.dispatch({
+ type: 'configs/start-add',
+ data: newConfig,
+ token: this.props.sessionToken
+ });
+ }
+
+ onConfigChecked(index, event) {
+ const selectedConfigs = Object.assign([], this.state.selectedConfigs);
+ for (let key in selectedConfigs) {
+ if (selectedConfigs[key] === index) {
+ // update existing entry
+ if (event.target.checked) {
+ return;
+ }
+
+ selectedConfigs.splice(key, 1);
+
+ this.setState({ selectedConfigs: selectedConfigs });
+ return;
+ }
+ }
+
+ // add new entry
+ if (event.target.checked === false) {
+ return;
+ }
+
+ selectedConfigs.push(index);
+ this.setState({ selectedConfigs: selectedConfigs });
+ }
+
+ usesExternalIC(index) {
+ for (let component of this.props.ics) {
+ if (component.id === this.props.configs[index].icID) {
+ if (component.managedexternally === true) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ getICName(icID) {
+ for (let ic of this.props.ics) {
+ if (ic.id === icID) {
+ return ic.name || ic.uuid;
+ }
+ }
+ }
+
+ /* ##############################################
+ * Signal modification methods
+ ############################################## */
+
+ closeEditSignalsModal(direction) {
+
+ // reload the config
+ AppDispatcher.dispatch({
+ type: 'configs/start-load',
+ data: this.state.modalConfigData.id,
+ token: this.props.sessionToken
+ });
+
+ if (direction === "in") {
+ this.setState({ editInputSignalsModal: false });
+ } else if (direction === "out") {
+ this.setState({ editOutputSignalsModal: false });
+ }
+ }
+
+ signalsAutoConf(index) {
+ let componentConfig = this.props.configs[index];
+ // determine apiurl of infrastructure component
+ let ic = this.props.ics.find(ic => ic.id === componentConfig.icID)
+ if (!ic.type.includes("villas-node")) {
+ let message = "Cannot autoconfigure signals for IC type " + ic.type + " of category " + ic.category + ". This is only possible for gateway ICs of type 'VILLASnode'."
+ console.warn(message);
+
+ const SIGNAL_AUTOCONF_WARN_NOTIFICATION = {
+ title: 'Failed to load signal config for IC ' + ic.name,
+ message: message,
+ level: 'warning'
+ };
+ NotificationsDataManager.addNotification(SIGNAL_AUTOCONF_WARN_NOTIFICATION);
+ return;
+ }
+
+ let splitWebsocketURL = ic.websocketurl.split("/")
+
+ AppDispatcher.dispatch({
+ type: 'signals/start-autoconfig',
+ url: ic.apiurl + "/nodes",
+ socketname: splitWebsocketURL[splitWebsocketURL.length - 1],
+ token: this.props.sessionToken,
+ configID: componentConfig.id
+ });
+
+ }
+
+ startPintura(configIndex) {
+ let config = this.props.configs[configIndex];
+
+ // get xml / CIM file
+ let files = []
+ for (let id of config.fileIDs) {
+ for (let file of this.props.files) {
+ if (file.id === id && ['xml'].some(e => file.type.includes(e))) {
+ files.push(file);
+ }
+ }
+ }
+
+ if (files.length > 1) {
+ // more than one CIM file...
+ console.warn("There is more than one CIM file selected in this component configuration. I will open them all in a separate tab.")
+ }
+
+ let baseURL = 'aaa.bbb.ccc.ddd/api/v2/files/'
+ for (let file of files) {
+ // endpoint param serves for download and upload of CIM file, token is required for authentication
+ let params = {
+ token: this.props.sessionToken,
+ endpoint: baseURL + String(file.id),
+ }
+
+ // TODO start Pintura for editing CIM/ XML file from here
+ console.warn("Starting Pintura... and nothing happens so far :-) ", params)
+ }
+ }
+
+ render() {
+ const buttonStyle = {
+ marginLeft: '10px',
+ }
+
+ const iconStyle = {
+ height: '30px',
+ width: '30px'
+ }
+
+ return (
+
+ {/*Component Configurations table*/}
+
Component Configurations
+
+ this.addConfig()}
+ icon='plus'
+ disabled={this.props.locked}
+ hidetooltip={this.props.locked}
+ buttonStyle={buttonStyle}
+ iconStyle={iconStyle}
+ />
+ this.setState({ importConfigModal: true })}
+ icon='upload'
+ disabled={this.props.locked}
+ hidetooltip={this.props.locked}
+ buttonStyle={buttonStyle}
+ iconStyle={iconStyle}
+ />
+
+
+
+ !this.usesExternalIC(index)}
+ onChecked={(index, event) => this.onConfigChecked(index, event)}
+ width={20}
+ />
+ {this.props.currentUser.role === "Admin" ?
+
+ : <>>
+ }
+
+ this.setState({ editOutputSignalsModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })}
+ width={150}
+ locked={this.props.locked}
+ />
+ this.setState({ editInputSignalsModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })}
+ width={150}
+ locked={this.props.locked}
+ />
+ this.signalsAutoConf(index)}
+ width={170}
+ locked={this.props.locked}
+ />
+ this.getICName(icID)}
+ width={200}
+ />
+ this.setState({ editConfigModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })}
+ onDelete={(index) => this.setState({ deleteConfigModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })}
+ onExport={index => this.exportConfig(index)}
+ onDuplicate={index => this.duplicateConfig(index)}
+ locked={this.props.locked}
+ />
+
+
+ {this.state.ExternalICInUse ?
+
+ this.copyConfig(index)}
+ token = {this.props.sessionToken}
+ actions={[
+ { id: '0', title: 'Start', data: { action: 'start' } },
+ { id: '1', title: 'Stop', data: { action: 'stop' } },
+ { id: '2', title: 'Pause', data: { action: 'pause' } },
+ { id: '3', title: 'Resume', data: { action: 'resume' } }
+ ]} />
+
+ :
+ }
+
+
+
+
this.closeEditConfigModal(data)}
+ config={this.state.modalConfigData}
+ ics={this.props.ics}
+ files={this.props.files}
+ sessionToken={this.props.sessionToken}
+ />
+ this.importConfig(data)}
+ ics={this.props.ics}
+ />
+ this.closeDeleteConfigModal(c)}
+ />
+ this.closeEditSignalsModal(direction)}
+ direction="Output"
+ signals={this.props.signals}
+ configID={this.state.modalConfigData.id}
+ sessionToken={this.props.sessionToken}
+ />
+ this.closeEditSignalsModal(direction)}
+ direction="Input"
+ signals={this.props.signals}
+ configID={this.state.modalConfigData.id}
+ sessionToken={this.props.sessionToken}
+ />
+
+ )
+ }
+}
+
+export default ConfigTable;
diff --git a/src/dashboard/dashboard-button-group.js b/src/dashboard/dashboard-button-group.js
index 20a8994..ddacfa0 100644
--- a/src/dashboard/dashboard-button-group.js
+++ b/src/dashboard/dashboard-button-group.js
@@ -17,115 +17,77 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { Button,OverlayTrigger, Tooltip } from 'react-bootstrap';
-import Icon from "../common/icon";
+import IconButton from '../common/icon-button';
+
+const buttonStyle = {
+ marginLeft: '12px',
+ height: '44px',
+ width: '35px',
+};
+
+const iconStyle = {
+ height: '25px',
+ width: '25px'
+}
+
+let buttonkey = 0;
class DashboardButtonGroup extends React.Component {
- render() {
- const buttonStyle = {
- marginLeft: '12px',
- height: '44px',
- width : '35px',
- };
- const iconStyle = {
- height: '25px',
- width : '25px'
+ getBtn(icon, tooltip, clickFn, locked = false) {
+ if (locked) {
+ return
+ } else {
+ return
}
+ }
+ render() {
const buttons = [];
- let key = 0;
-
- /*if (this.props.fullscreen) {
- return null;
- }*/
+ buttonkey = 0;
if (this.props.editing) {
- buttons.push(
- Save changes } >
-
- ,
- Discard changes } >
-
-
- );
+ buttons.push(this.getBtn("save", "Save changes", this.props.onSave));
+ buttons.push(this.getBtn("times", "Discard changes", this.props.onCancel));
} else {
if (this.props.fullscreen !== true) {
- buttons.push(
-
- Change to fullscreen view } >
-
-
- );
+ buttons.push(this.getBtn("expand", "Change to fullscreen view", this.props.onFullscreen));
} else {
- buttons.push(
- Back to normal view } >
-
-
- );
+ buttons.push(this.getBtn("compress", "Back to normal view", this.props.onFullscreen));
}
if (this.props.paused) {
- buttons.push(
- Continue simulation } >
-
-
- );
+ buttons.push(this.getBtn("play", "Continue simulation", this.props.onUnpause));
} else {
- buttons.push(
- Pause simulation } >
-
-
- );
+ buttons.push(this.getBtn("pause", "Pause simulation", this.props.onPause));
}
if (this.props.fullscreen !== true) {
- buttons.push(
- Add, edit or delete files of scenario }>
-
-
- );
-
- buttons.push(
- Add, edit or delete input signals }>
-
-
- );
-
- buttons.push(
- Add, edit or delete output signals }>
-
-
- );
-
- buttons.push(
- Add widgets and edit layout }>
-
-
- );
+ let tooltip = this.props.locked ? "View files of scenario" : "Add, edit or delete files of scenario";
+ buttons.push(this.getBtn("file", tooltip, this.props.onEditFiles));
+ buttons.push(this.getBtn("sign-in-alt", "Add, edit or delete input signals", this.props.onEditInputSignals, this.props.locked));
+ buttons.push(this.getBtn("sign-out-alt", "Add, edit or delete output signals", this.props.onEditOutputSignals, this.props.locked));
+ buttons.push(this.getBtn("pen", "Add widgets and edit layout", this.props.onEdit, this.props.locked));
}
}
diff --git a/src/dashboard/dashboard-table.js b/src/dashboard/dashboard-table.js
new file mode 100644
index 0000000..589366b
--- /dev/null
+++ b/src/dashboard/dashboard-table.js
@@ -0,0 +1,246 @@
+/**
+ * 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 React, {Component} from "react";
+import FileSaver from 'file-saver';
+import IconButton from "../common/icon-button";
+import Table from "../common/table";
+import TableColumn from "../common/table-column";
+import NewDashboardDialog from "./new-dashboard";
+import EditDashboardDialog from "./edit-dashboard";
+import ImportDashboardDialog from "./import-dashboard";
+import DeleteDialog from "../common/dialogs/delete-dialog";
+import AppDispatcher from "../common/app-dispatcher";
+
+class DashboardTable extends Component {
+
+ constructor() {
+ super();
+
+ this.state = {
+ newDashboardModal: false,
+ deleteDashboardModal: false,
+ importDashboardModal: false,
+ modalDashboardData: {},
+ dashboardEditModal: false,
+ }
+ }
+
+ closeNewDashboardModal(data) {
+ this.setState({ newDashboardModal: false });
+ if (data) {
+ // TODO: 'newDashboard' not used, check this
+ let newDashboard = data;
+ // add default grid value and scenarioID
+ newDashboard["grid"] = 15;
+ newDashboard["scenarioID"] = this.props.scenario.id;
+
+ AppDispatcher.dispatch({
+ type: 'dashboards/start-add',
+ data,
+ token: this.props.sessionToken,
+ });
+ }
+ }
+
+ closeEditDashboardModal(data) {
+ this.setState({ dashboardEditModal: false });
+
+ let editDashboard = this.state.modalDashboardData;
+
+ if (data != null) {
+ editDashboard.name = data.name;
+ AppDispatcher.dispatch({
+ type: 'dashboards/start-edit',
+ data: editDashboard,
+ token: this.props.sessionToken
+ });
+ }
+ }
+
+ closeDeleteDashboardModal(confirmDelete) {
+ this.setState({ deleteDashboardModal: false });
+
+ if (confirmDelete === false) {
+ return;
+ }
+
+ AppDispatcher.dispatch({
+ type: 'dashboards/start-remove',
+ data: this.state.modalDashboardData,
+ token: this.props.sessionToken,
+ });
+ }
+
+ closeImportDashboardModal(data) {
+ this.setState({ importDashboardModal: false });
+
+ if (data) {
+ let newDashboard = JSON.parse(JSON.stringify(data));
+ newDashboard["scenarioID"] = this.props.scenario.id;
+
+ AppDispatcher.dispatch({
+ type: 'dashboards/start-add',
+ data: newDashboard,
+ token: this.props.sessionToken,
+ });
+ }
+ }
+
+ copyDashboard(index) {
+ let dashboard = JSON.parse(JSON.stringify(this.props.dashboards[index]));
+
+ let widgets = JSON.parse(JSON.stringify(this.props.widgets.filter(w => w.dashboardID === parseInt(dashboard.id, 10))));
+ widgets.forEach((widget) => {
+ delete widget.dashboardID;
+ delete widget.id;
+ })
+ dashboard["widgets"] = widgets;
+ delete dashboard.scenarioID;
+ delete dashboard.id;
+
+ return dashboard;
+ }
+
+ exportDashboard(index) {
+ let dashboard = this.copyDashboard(index);
+
+ // show save dialog
+ const blob = new Blob([JSON.stringify(dashboard, null, 2)], { type: 'application/json' });
+ FileSaver.saveAs(blob, 'dashboard - ' + dashboard.name + '.json');
+ }
+
+ duplicateDashboard(index) {
+ let newDashboard = this.copyDashboard(index);
+ newDashboard.scenarioID = this.props.scenario.id;
+ newDashboard.name = newDashboard.name + '_copy';
+
+ AppDispatcher.dispatch({
+ type: 'dashboards/start-add',
+ data: newDashboard,
+ token: this.props.sessionToken,
+ });
+ }
+
+ render() {
+ const buttonStyle = {
+ marginLeft: '10px',
+ }
+
+ const iconStyle = {
+ height: '30px',
+ width: '30px'
+ }
+
+ return (
+
+ {/*Dashboard table*/}
+
Dashboards
+
+ this.setState({newDashboardModal: true})}
+ icon='plus'
+ disabled={this.props.locked}
+ hidetooltip={this.props.locked}
+ buttonStyle={buttonStyle}
+ iconStyle={iconStyle}
+ />
+ this.setState({importDashboardModal: true})}
+ icon='upload'
+ disabled={this.props.locked}
+ hidetooltip={this.props.locked}
+ buttonStyle={buttonStyle}
+ iconStyle={iconStyle}
+ />
+
+
+
+ {this.props.currentUser.role === "Admin" ?
+
+ : <>>
+ }
+
+
+
+ this.setState({
+ dashboardEditModal: true,
+ modalDashboardData: this.props.dashboards[index]
+ })}
+ onDelete={(index) => this.setState({
+ deleteDashboardModal: true,
+ modalDashboardData: this.props.dashboards[index],
+ modalDashboardIndex: index
+ })}
+ onExport={index => this.exportDashboard(index)}
+ onDuplicate={index => this.duplicateDashboard(index)}
+ locked={this.props.locked}
+ />
+
+
+
this.closeNewDashboardModal(data)}
+ />
+ this.closeEditDashboardModal(data)}
+ />
+ this.closeImportDashboardModal(data)}
+ />
+ this.closeDeleteDashboardModal(e)}
+ />
+
+
+ )
+ }
+}
+
+export default DashboardTable;
diff --git a/src/dashboard/dashboard.js b/src/dashboard/dashboard.js
index fe3ca4f..ee838f3 100644
--- a/src/dashboard/dashboard.js
+++ b/src/dashboard/dashboard.js
@@ -27,6 +27,7 @@ import WidgetContextMenu from '../widget/widget-context-menu';
import WidgetToolbox from '../widget/widget-toolbox';
import WidgetArea from '../widget/widget-area';
import DashboardButtonGroup from './dashboard-button-group';
+import IconToggleButton from '../common/icon-toggle-button';
import DashboardStore from './dashboard-store';
import SignalStore from '../signal/signal-store'
@@ -35,6 +36,8 @@ import WidgetStore from '../widget/widget-store';
import ICStore from '../ic/ic-store'
import ConfigStore from '../componentconfig/config-store'
import AppDispatcher from '../common/app-dispatcher';
+import ScenarioStore from '../scenario/scenario-store';
+
import 'react-contexify/dist/ReactContexify.min.css';
import WidgetContainer from '../widget/widget-container';
@@ -45,7 +48,7 @@ class Dashboard extends Component {
static lastWidgetKey = 0;
static webSocketsOpened = false;
static getStores() {
- return [DashboardStore, FileStore, WidgetStore, SignalStore, ConfigStore, ICStore];
+ return [DashboardStore, FileStore, WidgetStore, SignalStore, ConfigStore, ICStore, ScenarioStore];
}
static calculateState(prevState, props) {
@@ -80,9 +83,14 @@ class Dashboard extends Component {
// filter component configurations to the ones that belong to this scenario
let configs = [];
let files = [];
+ let locked = false;
if (dashboard !== undefined) {
configs = ConfigStore.getState().filter(config => config.scenarioID === dashboard.scenarioID);
files = FileStore.getState().filter(file => file.scenarioID === dashboard.scenarioID);
+ let scenario = ScenarioStore.getState().find(s => s.id === dashboard.scenarioID);
+ if (scenario) {
+ locked = scenario.isLocked;
+ }
if (dashboard.height === 0) {
dashboard.height = 400;
}
@@ -144,6 +152,7 @@ class Dashboard extends Component {
widgetOrigIDs: prevState.widgetOrigIDs || [],
maxWidgetHeight: maxHeight || null,
+ locked,
};
}
@@ -177,11 +186,22 @@ class Dashboard extends Component {
componentDidUpdate(prevProps: Readonly, prevState: Readonly, snapshot: SS) {
// open web sockets if ICs are already known and sockets are not opened yet
if (this.state.ics !== undefined && !Dashboard.webSocketsOpened) {
- if (this.state.ics.length > 0) {
- console.log("Starting to open IC websockets:", this.state.ics);
+ // only open sockets of ICs with configured input or output signals
+ let relevantICs = this.state.ics.filter(ic => {
+ let result = false;
+ this.state.configs.forEach(config => {
+ if(ic.id === config.icID && (config.inputLength !== 0 || config.outputLength !== 0)){
+ result = true;
+ }
+ })
+ return result;
+ })
+
+ if (relevantICs.length > 0) {
+ console.log("Starting to open IC websockets:", relevantICs);
AppDispatcher.dispatch({
type: 'ics/open-sockets',
- data: this.state.ics
+ data: relevantICs
});
Dashboard.webSocketsOpened = true;
@@ -205,6 +225,13 @@ class Dashboard extends Component {
param: '?scenarioID=' + this.state.dashboard.scenarioID,
token: this.state.sessionToken
});
+
+ // load scenario for 'isLocked' value
+ AppDispatcher.dispatch({
+ type: 'scenarios/start-load',
+ data: this.state.dashboard.scenarioID,
+ token: this.state.sessionToken
+ });
}
}
@@ -471,66 +498,65 @@ class Dashboard extends Component {
return
{"Loading Dashboard..."}
}
+ const buttonStyle = {
+ marginLeft: '10px',
+ }
+
+ const iconStyle = {
+ height: '25px',
+ width: '25px'
+ }
+
const grid = this.state.dashboard.grid;
const boxClasses = classNames('section', 'box', { 'fullscreen-padding': this.props.isFullscreen });
let draggable = this.state.editing;
let dropZoneHeight = this.state.dashboard.height;
- return
+ return (
-
{this.state.dashboard.name}
+
+ {this.state.dashboard.name}
+
+
+
+
-
-
+
+
-
e.preventDefault()}>
- {this.state.editing &&
-
- }
- {!draggable ? (
-
- {this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => (
-
-
-
- ))}
-
- ) : (
-
+ e.preventDefault()}>
+ {this.state.editing &&
+
+ }
+ {!draggable ? (
+
{this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => (
-
+
-
+
))}
+ ) : (
+
+ {this.state.widgets != null && Object.keys(this.state.widgets).map(widgetKey => (
+
+
+
+ ))}
+
-
+ )}
-
+
- this.closeEditSignalsModal(direction)}
- direction="Output"
- signals={this.state.signals}
- configID={null}
- configs={this.state.configs}
- sessionToken={this.state.sessionToken}
- />
- this.closeEditSignalsModal(direction)}
- direction="Input"
- signals={this.state.signals}
- configID={null}
- configs={this.state.configs}
- sessionToken={this.state.sessionToken}
- />
+
+
+ this.closeEditSignalsModal(direction)}
+ direction="Output"
+ signals={this.state.signals}
+ configID={null}
+ configs={this.state.configs}
+ sessionToken={this.state.sessionToken}
+ />
+ this.closeEditSignalsModal(direction)}
+ direction="Input"
+ signals={this.state.signals}
+ configID={null}
+ configs={this.state.configs}
+ sessionToken={this.state.sessionToken}
+ />
+
+
+
-
;
+ );
}
}
diff --git a/src/file/edit-files.js b/src/file/edit-files.js
index 1ec0276..bca36b6 100644
--- a/src/file/edit-files.js
+++ b/src/file/edit-files.js
@@ -106,10 +106,12 @@ class EditFilesDialog extends React.Component {
marginTop: '-40px'
};
+ let title = this.props.locked ? "View files of scenario" : "Edit Files of Scenario";
+
return (