1
0
Fork 0
mirror of https://git.rwth-aachen.de/acs/public/villas/web/ synced 2025-03-09 00:00:01 +01:00

lock scenarios as admin user, see #309

This commit is contained in:
irismarie 2021-04-09 19:22:12 +02:00
parent 726f6767d7
commit c20f783689
12 changed files with 130 additions and 64 deletions

View file

@ -42,6 +42,7 @@ class IconButton extends React.Component {
variant='light'
onClick={this.props.onClick}
style={altButtonStyle}
disabled={this.props.disabled}
>
<Icon
icon={this.props.icon}

View file

@ -28,6 +28,8 @@ class TableColumn extends Component {
showDeleteButton: null,
exportButton: false,
duplicateButton: false,
isLocked: null,
locked: false,
link: '/',
linkKey: '',
dataIndex: false,

View file

@ -125,6 +125,8 @@ class CustomTable extends Component {
cell.push(index);
}
let isLocked = child.props.locked || (child.props.isLocked != null && child.props.isLocked(index));
// add buttons
let showEditButton = child.props.showEditButton !== null && child.props.showEditButton !== undefined
? child.props.showEditButton(index)
@ -140,7 +142,7 @@ class CustomTable extends Component {
<Button
variant='table-control-button'
onClick={() => child.props.onEdit(index)}
disabled={child.props.onEdit == null} >
disabled={child.props.onEdit == null || isLocked} >
<Icon icon='edit' />
</Button>
</OverlayTrigger>
@ -190,7 +192,7 @@ class CustomTable extends Component {
<Button
variant='table-control-button'
onClick={() => child.props.onDuplicate(index)}
disabled={child.props.onDuplicate == null}>
disabled={child.props.onDuplicate == null || isLocked}>
<Icon icon='copy' />
</Button>
</OverlayTrigger>
@ -206,7 +208,7 @@ class CustomTable extends Component {
<Button
variant='table-control-button'
onClick={() => child.props.onAddRemove(index)}
disabled={child.props.onAddRemove == null}>
disabled={child.props.onAddRemove == null || isLocked}>
<Icon icon='file' />
</Button>
</OverlayTrigger>
@ -242,7 +244,7 @@ class CustomTable extends Component {
<Button
variant='table-control-button'
onClick={() => child.props.onDelete(index)}
disabled={child.props.onDelete == null}>
disabled={child.props.onDelete == null || isLocked}>
<Icon icon='trash' />
</Button>
</OverlayTrigger>

View file

@ -308,12 +308,14 @@ class ConfigTable extends Component {
tooltip='Add Component Configuration'
onClick={() => this.addConfig()}
icon='plus'
disabled={this.props.locked}
/>
<IconButton
ikey={1}
tooltip='Import Component Configuration'
onClick={() => this.setState({ importConfigModal: true })}
icon='upload'
disabled={this.props.locked}
/>
</span>
</h2>
@ -343,6 +345,7 @@ class ConfigTable extends Component {
editButton
onEdit={index => this.setState({ editOutputSignalsModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })}
width={150}
locked={this.props.locked}
/>
<TableColumn
title='# Input Signals'
@ -350,6 +353,7 @@ class ConfigTable extends Component {
editButton
onEdit={index => this.setState({ editInputSignalsModal: true, modalConfigData: this.props.configs[index], modalConfigIndex: index })}
width={150}
locked={this.props.locked}
/>
<TableColumn
title='Import Signals'
@ -375,6 +379,7 @@ class ConfigTable extends Component {
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}
/>
</Table>

View file

@ -91,9 +91,10 @@ class DashboardButtonGroup extends React.Component {
}
if (this.props.fullscreen !== true) {
let filesTooltip = this.props.locked ? "View files of scenario" : "Add, edit or delete files of scenario";
buttons.push(
<OverlayTrigger key={key++} placement={'bottom'}
overlay={<Tooltip id={`tooltip-${"file"}`}> Add, edit or delete files of scenario </Tooltip>}>
overlay={<Tooltip id={`tooltip-${"file"}`}>{filesTooltip}</Tooltip>}>
<Button key={key} variant='light' size="lg" onClick={this.props.onEditFiles} style={buttonStyle}>
<Icon icon="file" classname='icon-color' style={iconStyle}/>
</Button>
@ -120,7 +121,7 @@ class DashboardButtonGroup extends React.Component {
buttons.push(
<OverlayTrigger key={key++} placement={'bottom'}
overlay={<Tooltip id={`tooltip-${"layout"}`}> Add widgets and edit layout </Tooltip>}>
<Button key={key} variant='light' size="lg" onClick={this.props.onEdit} style={buttonStyle}>
<Button key={key} variant='light' size="lg" onClick={this.props.onEdit} style={buttonStyle} disabled={this.props.locked}>
<Icon icon="pen" classname='icon-color' style={iconStyle}/>
</Button>
</OverlayTrigger>

View file

@ -148,12 +148,14 @@ class DashboardTable extends Component {
tooltip='Add Dashboard'
onClick={() => this.setState({newDashboardModal: true})}
icon='plus'
disabled={this.props.locked}
/>
<IconButton
ikey={1}
tooltip='Import Dashboard'
onClick={() => this.setState({importDashboardModal: true})}
icon='upload'
disabled={this.props.locked}
/>
</span>
</h2>
@ -198,6 +200,7 @@ class DashboardTable extends Component {
})}
onExport={index => this.exportDashboard(index)}
onDuplicate={index => this.duplicateDashboard(index)}
locked={this.props.locked}
/>
</Table>

View file

@ -35,6 +35,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 +47,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 +82,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 +151,7 @@ class Dashboard extends Component {
widgetOrigIDs: prevState.widgetOrigIDs || [],
maxWidgetHeight: maxHeight || null,
locked,
};
}
@ -205,6 +213,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
});
}
}
@ -482,6 +497,7 @@ class Dashboard extends Component {
</div>
<DashboardButtonGroup
locked={this.state.locked}
editing={this.state.editing}
onEdit={this.startEditing.bind(this)}
fullscreen={this.props.isFullscreen}
@ -567,6 +583,7 @@ class Dashboard extends Component {
signals={this.state.signals}
files={this.state.files}
scenarioID={this.state.dashboard.scenarioID}
locked={this.state.locked}
/>
<EditSignalMappingDialog

View file

@ -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 (
<Dialog
show={this.props.show}
title="Edit Files of Scenario"
title={title}
buttonTitle="Close"
onClose={() => this.onClose()}
blendOutCancel = {true}
@ -139,6 +141,7 @@ class EditFilesDialog extends React.Component {
onDelete={(index) => this.deleteFile(index)}
editButton
onEdit={index => this.setState({ editModal: true, modalFile: this.props.files[index] })}
locked={this.props.locked}
/>
</Table>
@ -146,13 +149,17 @@ class EditFilesDialog extends React.Component {
<h5>Add file</h5>
<Row>
<Col xs lg="4">
<Form.Control type='file' onChange={(event) => this.selectUploadFile(event)} />
<Form.Control
type='file'
onChange={(event) => this.selectUploadFile(event)}
disabled={this.props.locked}
/>
</Col>
<Col xs lg="2">
<span className='solid-button'>
<Button
variant='secondary'
disabled={this.state.uploadFile === null}
disabled={this.state.uploadFile === null || this.props.locked}
onClick={() => this.startFileUpload()}>
Upload
</Button>

View file

@ -165,6 +165,7 @@ class ResultTable extends Component {
tooltip='Add Result'
onClick={() => this.setState({ newResultModal: true })}
icon='plus'
disabled={this.props.locked}
/>
</span>
</h2>
@ -208,6 +209,7 @@ class ResultTable extends Component {
onEdit={index => this.setState({ editResultsModal: true, modalResultsIndex: index })}
onDownloadAll={(index) => this.downloadResultData(this.props.results[index])}
onDelete={(index) => this.setState({ deleteResultsModal: true, modalResultsData: this.props.results[index], modalResultsIndex: index })}
locked={this.props.locked}
/>
</Table>

View file

@ -124,6 +124,7 @@ class ScenarioUsersTable extends Component {
deleteUserName: this.props.scenario.users[index].username,
modalUserIndex: index
})}
locked={this.props.locked}
/>
</Table>
@ -145,6 +146,7 @@ class ScenarioUsersTable extends Component {
variant='light'
type="submit"
style={altButtonStyle}
disabled={this.props.locked}
onClick={() => this.addUser()}>
<Icon icon="plus" classname={'icon-color'} style={iconStyle} />
</Button>

View file

@ -126,11 +126,13 @@ class Scenario extends React.Component {
return <h1>Loading Scenario...</h1>;
}
let tooltip = this.state.scenario.isLocked ? "View files of scenario" : "Add, edit or delete files of scenario";
return <div className='section'>
<div className='section-buttons-group-right'>
<IconButton
ikey="0"
tooltip="Add, edit or delete files of scenario"
tooltip={tooltip}
onClick={this.onEditFiles.bind(this)}
icon="file"
/>
@ -144,6 +146,7 @@ class Scenario extends React.Component {
signals={this.state.signals}
files={this.state.files}
scenarioID={this.state.scenario.id}
locked={this.state.scenario.isLocked}
/>
<ConfigTable
@ -155,6 +158,7 @@ class Scenario extends React.Component {
sessionToken={this.state.sessionToken}
currentUser={this.state.currentUser}
tableHeadingStyle={tableHeadingStyle}
locked={this.state.scenario.isLocked}
/>
<DashboardTable
@ -164,6 +168,7 @@ class Scenario extends React.Component {
sessionToken={this.state.sessionToken}
currentUser={this.state.currentUser}
tableHeadingStyle={tableHeadingStyle}
locked={this.state.scenario.isLocked}
/>
<ResultTable
@ -172,6 +177,7 @@ class Scenario extends React.Component {
scenario={this.state.scenario}
sessionToken={this.state.sessionToken}
tableHeadingStyle={tableHeadingStyle}
locked={this.state.scenario.isLocked}
/>
<ScenarioUsersTable
@ -179,6 +185,7 @@ class Scenario extends React.Component {
currentUser={this.state.currentUser}
sessionToken={this.state.sessionToken}
tableHeadingStyle={tableHeadingStyle}
locked={this.state.scenario.isLocked}
/>
</div>

View file

@ -73,7 +73,7 @@ class Scenarios extends Component {
}
closeNewModal(data) {
if(data) {
if (data) {
AppDispatcher.dispatch({
type: 'scenarios/start-add',
data: data,
@ -218,7 +218,7 @@ class Scenarios extends Component {
jsonObj["configs"] = this.getConfigs(scenario.id);
jsonObj["dashboards"] = this.getDashboards(scenario.id);
if(jsonObj) {
if (jsonObj) {
AppDispatcher.dispatch({
type: 'scenarios/start-add',
data: jsonObj,
@ -227,68 +227,85 @@ class Scenarios extends Component {
}
}
modifyRunningColumn(running){
return <Icon icon={ running ? 'check' : 'times' } />
isLocked(index) {
return this.state.scenarios[index].isLocked;
}
onLock(scenario) {
let data = {};
data.id = scenario.id;
data.isLocked = !scenario.isLocked;
AppDispatcher.dispatch({
type: 'scenarios/start-edit',
data,
token: this.state.sessionToken
});
}
render() {
return <div className='section'>
<h1>Scenarios
<h1>Scenarios
<span className='icon-button'>
<IconButton
ikey={0}
tooltip='Add Scenario'
onClick={() => this.setState({ newModal: true })}
icon='plus'
/>
<IconButton
ikey={1}
tooltip='Import Scenario'
onClick={() => this.setState({ importModal: true })}
icon='upload'
/>
</span>
</h1>
<Table data={this.state.scenarios}>
{this.state.currentUser.role === "Admin" ?
<TableColumn
title='ID'
dataKey='id'
/>
: <></>
}
<TableColumn
title='Name'
dataKey='name'
link='/scenarios/'
linkKey='id'
<IconButton
ikey={0}
tooltip='Add Scenario'
onClick={() => this.setState({ newModal: true })}
icon='plus'
/>
<TableColumn
title='Running'
dataKey='running'
modifier={(running) => this.modifyRunningColumn(running)}
<IconButton
ikey={1}
tooltip='Import Scenario'
onClick={() => this.setState({ importModal: true })}
icon='upload'
/>
</span>
</h1>
<Table data={this.state.scenarios}>
{this.state.currentUser.role === "Admin" ?
<TableColumn
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)}
title='ID'
dataKey='id'
/>
</Table>
: <></>
}
<TableColumn
title='Name'
dataKey='name'
link='/scenarios/'
linkKey='id'
/>
{this.state.currentUser.role === "Admin" ?
<TableColumn
title='Locked'
checkbox
checkboxKey='isLocked'
onChecked={(index, event) => this.onLock(index)}
/>
: <></>
}
<TableColumn
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} />
<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>;
}
}