mirror of
https://git.rwth-aachen.de/acs/public/villas/web/
synced 2025-03-09 00:00:01 +01:00
Add image widget
Add file upload, used for image widget atm Image widget is buggy atm
This commit is contained in:
parent
73a576ab88
commit
93da46973d
10 changed files with 280 additions and 8 deletions
|
@ -82,6 +82,24 @@ class RestAPI {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
upload(url, data, token) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var req = request.post(url).send(data);
|
||||
|
||||
if (token != null) {
|
||||
req.set('x-access-token', token);
|
||||
}
|
||||
|
||||
req.end(function (error, res) {
|
||||
if (res == null || res.status !== 200) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(JSON.parse(res.text));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new RestAPI();
|
||||
|
|
71
src/components/dialog/edit-widget-image.js
Normal file
71
src/components/dialog/edit-widget-image.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* File: edit-widget-value.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 04.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
import { FormGroup, FormControl, ControlLabel, Button } from 'react-bootstrap';
|
||||
|
||||
import AppDispatcher from '../../app-dispatcher';
|
||||
|
||||
class EditImageWidget extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
widget: {
|
||||
file: ''
|
||||
},
|
||||
fileList: null
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
this.setState({ widget: nextProps.widget });
|
||||
}
|
||||
|
||||
startFileUpload() {
|
||||
// get selected file
|
||||
var formData = new FormData();
|
||||
|
||||
for (var key in this.state.fileList) {
|
||||
if (this.state.fileList.hasOwnProperty(key) && this.state.fileList[key] instanceof File) {
|
||||
formData.append(key, this.state.fileList[key]);
|
||||
}
|
||||
}
|
||||
|
||||
// upload files
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-upload',
|
||||
data: formData
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<FormGroup controlId="file">
|
||||
<ControlLabel>Image</ControlLabel>
|
||||
<FormControl componentClass="select" value={this.state.widget.file} onChange={(e) => this.props.handleChange(e)}>
|
||||
{this.props.files.map((file, index) => (
|
||||
<option key={index} value={file._id}>{file.name}</option>
|
||||
))}
|
||||
</FormControl>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup controlId="upload">
|
||||
<ControlLabel>Upload</ControlLabel>
|
||||
<FormControl type="file" onChange={(e) => this.setState({ fileList: e.target.files }) } />
|
||||
</FormGroup>
|
||||
|
||||
<Button bsSize="small" onClick={() => this.startFileUpload() }>Upload</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EditImageWidget;
|
|
@ -83,13 +83,13 @@ class EditWidgetDialog extends Component {
|
|||
} else if (this.props.widget.type === 'Table') {
|
||||
widgetDialog = <EditTableWidget widget={this.state.widget} validate={(id) => this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
|
||||
} else if (this.props.widget.type === 'Image') {
|
||||
widgetDialog = <EditImageWidget widget={this.state.widget} validate={(id) => this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
|
||||
widgetDialog = <EditImageWidget widget={this.state.widget} files={this.props.files} validate={(id) => this.validateForm(id)} simulation={this.props.simulation} handleChange={(e, index) => this.handleChange(e, index)} />;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog show={this.props.show} title="Edit Widget" buttonTitle="save" onClose={(c) => this.onClose(c)} onReset={() => this.resetState()} valid={this.valid}>
|
||||
<form>
|
||||
<form encType='multipart/form-data'>
|
||||
<FormGroup controlId="name" validationState={this.validateForm('name')}>
|
||||
<ControlLabel>Name</ControlLabel>
|
||||
<FormControl type="text" placeholder="Enter name" value={this.state.widget.name} onChange={(e) => this.handleChange(e)} />
|
||||
|
|
49
src/components/widget-image.js
Normal file
49
src/components/widget-image.js
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* File: widget-image.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 14.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import React, { Component } from 'react';
|
||||
|
||||
const API_URL = 'http://localhost:4000/';
|
||||
|
||||
class WidgetImage extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
file: null
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
// check if file is set
|
||||
if (nextProps.widget.file == null) {
|
||||
this.setState({ file: null });
|
||||
return;
|
||||
}
|
||||
|
||||
// get file by id
|
||||
nextProps.files.forEach(file => {
|
||||
if (file._id === nextProps.widget.file) {
|
||||
this.setState({ file: file });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
{this.state.file &&
|
||||
<img alt={this.state.file.name} style={{ width: this.props.widget.width - 20, height: this.props.widget.height - 20 }} src={API_URL + this.state.file.path} />
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default WidgetImage;
|
|
@ -20,11 +20,12 @@ import EditWidget from '../components/dialog/edit-widget';
|
|||
import VisualizationStore from '../stores/visualization-store';
|
||||
import ProjectStore from '../stores/project-store';
|
||||
import SimulationStore from '../stores/simulation-store';
|
||||
import FileStore from '../stores/file-store';
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
class Visualization extends Component {
|
||||
static getStores() {
|
||||
return [ VisualizationStore, ProjectStore, SimulationStore ];
|
||||
return [ VisualizationStore, ProjectStore, SimulationStore, FileStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState) {
|
||||
|
@ -36,6 +37,7 @@ class Visualization extends Component {
|
|||
visualizations: VisualizationStore.getState(),
|
||||
projects: ProjectStore.getState(),
|
||||
simulations: SimulationStore.getState(),
|
||||
files: FileStore.getState(),
|
||||
|
||||
visualization: prevState.visualization || {},
|
||||
project: prevState.project || null,
|
||||
|
@ -132,6 +134,9 @@ class Visualization extends Component {
|
|||
widget.width = 500;
|
||||
widget.height = 400;
|
||||
widget.time = 60
|
||||
} else if (item.name === 'Image') {
|
||||
widget.width = 200;
|
||||
widget.height = 200;
|
||||
}
|
||||
|
||||
var visualization = this.state.visualization;
|
||||
|
@ -280,7 +285,7 @@ class Visualization extends Component {
|
|||
<ToolboxItem name="Plot" type="widget" />
|
||||
<ToolboxItem name="Table" type="widget" />
|
||||
<ToolboxItem name="Label" type="widget" />
|
||||
<ToolboxItem name="Image" type="widget" disabled />
|
||||
<ToolboxItem name="Image" type="widget" />
|
||||
<ToolboxItem name="PlotTable" type="widget" />
|
||||
</div>
|
||||
}
|
||||
|
@ -305,7 +310,7 @@ class Visualization extends Component {
|
|||
</ContextMenu>
|
||||
))}
|
||||
|
||||
<EditWidget show={this.state.editModal} onClose={(data) => this.closeEdit(data)} widget={this.state.modalData} simulation={this.state.simulation} />
|
||||
<EditWidget show={this.state.editModal} onClose={(data) => this.closeEdit(data)} widget={this.state.modalData} simulation={this.state.simulation} files={this.state.files} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -12,37 +12,48 @@ import { Container } from 'flux/utils';
|
|||
import { ContextMenuTrigger } from 'react-contextmenu';
|
||||
import Rnd from 'react-rnd';
|
||||
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
import SimulatorDataStore from '../stores/simulator-data-store';
|
||||
import FileStore from '../stores/file-store';
|
||||
|
||||
import WidgetValue from '../components/widget-value';
|
||||
import WidgetPlot from '../components/widget-plot';
|
||||
import WidgetTable from '../components/widget-table';
|
||||
import WidgetLabel from '../components/widget-label';
|
||||
import WidgetPlotTable from '../components/widget-plot-table';
|
||||
import WidgetImage from '../components/widget-image';
|
||||
|
||||
import '../styles/widgets.css';
|
||||
|
||||
class Widget extends Component {
|
||||
static getStores() {
|
||||
return [ SimulatorDataStore ];
|
||||
return [ SimulatorDataStore, FileStore ];
|
||||
}
|
||||
|
||||
static calculateState(prevState) {
|
||||
if (prevState) {
|
||||
return {
|
||||
simulatorData: SimulatorDataStore.getState(),
|
||||
files: FileStore.getState(),
|
||||
|
||||
sequence: prevState.sequence + 1
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
simulatorData: SimulatorDataStore.getState(),
|
||||
files: FileStore.getState(),
|
||||
|
||||
sequence: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/start-load'
|
||||
});
|
||||
}
|
||||
|
||||
dragStop(event, ui) {
|
||||
// update widget
|
||||
var widget = this.props.data;
|
||||
|
@ -95,6 +106,8 @@ class Widget extends Component {
|
|||
element = <WidgetLabel widget={widget} />
|
||||
} else if (widget.type === 'PlotTable') {
|
||||
element = <WidgetPlotTable widget={widget} data={this.state.simulatorData} dummy={this.state.sequence} simulation={this.props.simulation} />
|
||||
} else if (widget.type === 'Image') {
|
||||
element = <WidgetImage widget={widget} files={this.state.files} />
|
||||
}
|
||||
|
||||
if (this.props.editing) {
|
||||
|
|
35
src/data-managers/files-data-manager.js
Normal file
35
src/data-managers/files-data-manager.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* File: files-data-manager.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 16.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import RestDataManager from './rest-data-manager';
|
||||
import RestAPI from '../api/rest-api';
|
||||
import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
class FilesDataManager extends RestDataManager {
|
||||
constructor() {
|
||||
super('file', '/files');
|
||||
}
|
||||
|
||||
upload(file) {
|
||||
RestAPI.upload(this.makeURL('/upload'), file).then(response => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/uploaded'
|
||||
});
|
||||
|
||||
console.log(response);
|
||||
}).catch(error => {
|
||||
AppDispatcher.dispatch({
|
||||
type: 'files/upload-error',
|
||||
error: error
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new FilesDataManager();
|
|
@ -8,5 +8,21 @@
|
|||
**********************************************************************************/
|
||||
|
||||
import RestDataManager from './rest-data-manager';
|
||||
import RestAPI from '../api/rest-api';
|
||||
//import AppDispatcher from '../app-dispatcher';
|
||||
|
||||
export default new RestDataManager('simulator', '/simulators');
|
||||
class SimulatorsDataManager extends RestDataManager {
|
||||
constructor() {
|
||||
super('simulator', '/simulators');
|
||||
}
|
||||
|
||||
isRunning(simulator) {
|
||||
RestAPI.get('http://localhost/nodes.json').then(response => {
|
||||
console.log(response);
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new SimulatorsDataManager();
|
||||
|
|
38
src/stores/file-store.js
Normal file
38
src/stores/file-store.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
/**
|
||||
* File: file-store.js
|
||||
* Author: Markus Grigull <mgrigull@eonerc.rwth-aachen.de>
|
||||
* Date: 16.03.2017
|
||||
* Copyright: 2017, Institute for Automation of Complex Power Systems, EONERC
|
||||
* This file is part of VILLASweb. All Rights Reserved. Proprietary and confidential.
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
**********************************************************************************/
|
||||
|
||||
import ArrayStore from './array-store';
|
||||
import FilesDataManager from '../data-managers/files-data-manager';
|
||||
|
||||
class FileStore extends ArrayStore {
|
||||
constructor() {
|
||||
super('files', FilesDataManager);
|
||||
}
|
||||
|
||||
reduce(state, action) {
|
||||
switch (action.type) {
|
||||
case 'files/start-upload':
|
||||
FilesDataManager.upload(action.data);
|
||||
return state;
|
||||
|
||||
case 'files/uploaded':
|
||||
console.log('ready uploaded');
|
||||
return state;
|
||||
|
||||
case 'files/upload-error':
|
||||
console.log(action.error);
|
||||
return state;
|
||||
|
||||
default:
|
||||
return super.reduce(state, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default new FileStore();
|
|
@ -10,4 +10,31 @@
|
|||
import ArrayStore from './array-store';
|
||||
import SimulatorsDataManager from '../data-managers/simulators-data-manager';
|
||||
|
||||
export default new ArrayStore('simulators', SimulatorsDataManager);
|
||||
class SimulatorStore extends ArrayStore {
|
||||
constructor() {
|
||||
super('simulators', SimulatorsDataManager);
|
||||
}
|
||||
|
||||
reduce(state, action) {
|
||||
// handle action
|
||||
state = super.reduce(state, action);
|
||||
|
||||
if (action.type === 'simulators/loaded') {
|
||||
// get simulator running state
|
||||
if (Array.isArray(action.data)) {
|
||||
action.data.forEach((simulator) => {
|
||||
//SimulatorsDataManager.isRunning(simulator);
|
||||
});
|
||||
} else {
|
||||
//SimulatorsDataManager.isRunning(action.data);
|
||||
}
|
||||
} else if (action.type === 'simulators/running') {
|
||||
// set running state
|
||||
console.log(action);
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
export default new SimulatorStore();
|
||||
|
|
Loading…
Add table
Reference in a new issue