1
0
Fork 0
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:
Markus Grigull 2017-03-16 21:21:57 +01:00
parent 73a576ab88
commit 93da46973d
10 changed files with 280 additions and 8 deletions

View file

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

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

View file

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

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

View file

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

View file

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

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

View file

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

View file

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