Commit 3d7aeef3 authored by Jaden DIEFENBAUGH's avatar Jaden DIEFENBAUGH
Browse files

added plotterparameter support but need to finish editor, #82

parent 02b0c85c
......@@ -75,6 +75,7 @@ class BeatEntity(Enum):
TOOLCHAIN = 'toolchains'
EXPERIMENT = 'experiments'
PLOTTER = 'plotters'
PLOTTERPARAMETER = 'plotterparameters'
def read_json(path):
......@@ -139,7 +140,8 @@ def generate_entity_tree(be):
BeatEntity.LIBRARY,
BeatEntity.ALGORITHM,
BeatEntity.TOOLCHAIN,
BeatEntity.PLOTTER
BeatEntity.PLOTTER,
BeatEntity.PLOTTERPARAMETER,
]
if be in user_and_name:
......@@ -194,8 +196,6 @@ def generate_entity_tree(be):
def generate_python_template(be, name, **kwargs):
"""Generates a template for a certain beat entity type with the given named arguments"""
if be in [BeatEntity.DATAFORMAT, BeatEntity.EXPERIMENT, BeatEntity.TOOLCHAIN]:
raise TypeError('Cannot create template for beat entity type "%s"' % be.value)
template_func = None
if be == BeatEntity.DATABASE:
template_func = templates.generate_database
......@@ -203,6 +203,9 @@ def generate_python_template(be, name, **kwargs):
template_func = templates.generate_library
elif be == BeatEntity.ALGORITHM:
template_func = templates.generate_algorithm
else:
raise TypeError('Cannot create template for beat entity type "%s"' % be.value)
s = template_func(**kwargs)
......@@ -286,6 +289,7 @@ class Home(Resource):
'toolchains',
'experiments',
'plotters',
'plotterparameters',
'settings',
'layout',
]
......
......@@ -34,6 +34,7 @@ import DatabaseEditorContainer from './database';
import ExperimentEditorContainer from './experiment';
import ToolchainEditorContainer from './toolchain';
import PlotterEditorContainer from './plotter';
import PlotterparameterEditorContainer from './plotterparameter';
type Props = {
match: any,
......@@ -163,6 +164,13 @@ export class EntityDetail extends React.Component<Props, State> {
saveFunc={this.saveChanges}
/>
}
{
this.props.match.params.entity === 'plotterparameter' &&
<PlotterparameterEditorContainer
data={this.props.getEntityObject()}
saveFunc={this.saveChanges}
/>
}
</TabPane>
<TabPane tabId='1'>
<Row>
......
......@@ -31,6 +31,7 @@ const HomeContent = () => (
<li>Toolchains</li>
<li>Experiments</li>
<li>Plotters</li>
<li>Plotterparameters</li>
</ul>
<p>
This web app edits the metadata of objects of all seven of these entities, but does not support editing code or documentation (e.g. editing Python or RST files).
......
......@@ -34,6 +34,7 @@ type Props = {
toolchain: BeatEntity[],
experiment: BeatEntity[],
plotter: BeatEntity[],
plotterparameter: BeatEntity[],
settings: BeatSettings,
unsavedChanges: boolean,
clearUnsaved: () => any,
......@@ -116,7 +117,7 @@ export class MainNav extends React.Component<Props, State> {
onClick={this.saveAllData}
title={this.props.unsavedChanges ? 'There may be unsaved changes on the web app. Click to save changes.' : 'There are no changes detected.'}
>
Write Changes To BEAT Prefix
Save All
</Button>
</NavItem>
</Nav>
......@@ -133,6 +134,7 @@ const mapStateToProps = state => ({
toolchain: Selectors.toolchainGet(state),
experiment: Selectors.experimentGet(state),
plotter: Selectors.plotterGet(state),
plotterparameter: Selectors.plotterparameterGet(state),
settings: Selectors.settingsGet(state),
unsavedChanges: Selectors.unsavedGet(state),
});
......
......@@ -7,6 +7,7 @@ import {
FormText,
Col,
Badge,
Row,
} from 'reactstrap';
import { connect } from 'react-redux';
......@@ -26,6 +27,7 @@ import { getValidAlgorithmObj } from '@helpers/beat';
import { getValidToolchainObj } from '@helpers/beat';
import { getValidExperimentObj } from '@helpers/beat';
import { getValidPlotterObj } from '@helpers/beat';
import { getValidPlotterparameterObj } from '@helpers/beat';
const getObjs = {
database: getValidDatabaseObj,
......@@ -35,6 +37,7 @@ const getObjs = {
toolchain: getValidToolchainObj,
experiment: getValidExperimentObj,
plotter: getValidPlotterObj,
plotterparameter: getValidPlotterparameterObj,
};
type Props = {
......@@ -399,6 +402,45 @@ export class NewEntityModal extends React.Component<Props, State> {
</Col>
</React.Fragment>
}
{/* plotterparameter */}
{ this.props.entity === 'plotterparameter' &&
<React.Fragment>
<Col sm={4}>
<Label>User</Label>
<CacheInput
type='text'
name='user'
placeholder={`Plotterparameter user...`}
value={this.state.nameSegs[0]}
onChange={(e) => this.handleInput(e.target.value)}
fieldTest
autoFocus
/>
</Col>
<Col sm={4}>
<Label>Name</Label>
<CacheInput
type='text'
name='name'
placeholder={`New plotterparameter name...`}
value={this.state.nameSegs[1]}
onChange={(e) => this.handleInput(undefined, e.target.value)}
fieldTest
/>
</Col>
<Col sm={4}>
<Label>Version</Label>
<CacheInput
type='text'
name='version'
placeholder={`Plotterparameter version...`}
value={this.state.nameSegs[2]}
validateFunc={(str) => `${ Number.parseInt(str) }` === str}
onChange={(e) => this.handleInput(undefined, undefined, e.target.value)}
/>
</Col>
</React.Fragment>
}
</FormGroup>
</Form>
</ModalBody>
......@@ -419,6 +461,7 @@ const mapStateToProps = (state, ownProps) => ({
data: Selectors[`${ ownProps.entity }Get`](state),
toolchains: Selectors.toolchainGet(state),
algorithms: Selectors.algorithmGet(state),
plotters: Selectors.plotterGet(state),
});
const mapDispatchToProps = (dispatch, ownProps) => ({
......
......@@ -95,7 +95,6 @@ export class PlotterEditor extends React.Component<Props, State> {
render = () => {
return (
<div>
<div className='d-flex'>
<Button
......@@ -474,7 +473,6 @@ export class PlotterEditor extends React.Component<Props, State> {
const mapStateToProps = (state, ownProps) => {
const obj = {
plotters: Selectors.plotterGet(state),
libraries: Selectors.libraryGet(state),
plotDfNames: Selectors.dataformatGet(state).map(df => df.name).filter(df => df.startsWith('plot/')),
};
......
// @flow
import * as React from 'react';
import {
Row,
Col,
Button,
Form, FormGroup,
Label, Input,
Card, CardHeader, CardBody,
TabContent, TabPane, Nav, NavItem, NavLink,
Alert,
UncontrolledDropdown, DropdownToggle, DropdownMenu,
InputGroup, InputGroupAddon,
} from 'reactstrap';
import { connect } from 'react-redux';
import cn from 'classnames';
import { changeObjFieldName, generateNewKey, jsonClone } from '@helpers';
import { BUILTIN_TYPES, ANALYZER_RESULT_TYPES, getValidPlotterparameterObj as getValidObj } from '@helpers/beat';
import type { BeatObject } from '@helpers/beat';
import * as Selectors from '@store/selectors.js';
import CacheInput from '../CacheInput.jsx';
import ValidSchemaBadge from '../ValidSchemaBadge.jsx';
import DeleteInputBtn from '../DeleteInputBtn.jsx';
import TypedField from '../TypedField.jsx';
import TemplateButton from '../EntityTemplateGenerationButton.jsx';
import InfoTooltip from '../InfoTooltip.jsx';
type Props = {
plotters: BeatObject[],
data: BeatObject,
libraries: BeatObject[],
saveFunc: (BeatObject) => any,
};
type State = {
cache: any,
choiceCache: string,
};
export class PlotterParameterEditor extends React.Component<Props, State> {
constructor(props: Props) {
//console.log(`Creating AlgDetail`);
super(props);
}
state = {
cache: getValidObj(this.props.data),
choiceCache: '',
}
componentWillReceiveProps (nextProps: Props) {
this.setState({
cache: getValidObj(nextProps.data),
});
}
setContents = (newContents: any) => {
this.setState({
cache: {
...this.state.cache,
contents: newContents,
}
});
}
updateDescription = (desc: string) => {
this.setContents({
...this.state.cache.contents,
description: desc,
});
}
getPlotter = () => {
const rx = /.+\/.+\/\d+/;
return Object.keys(this.state.cache.contents).find(k => rx.test(k));
}
updatePlotter = (plName: string) => {
const pl = this.props.plotters.find(pl => pl.name === plName);
if(!pl)
throw new Error(`Cannot find plotter with name ${ plName }`);
const oldPlotter = this.getPlotter();
if(oldPlotter === pl.name)
return;
const newContents = jsonClone(this.state.cache.contents);
if(oldPlotter)
delete newContents[oldPlotter];
newContents[pl.name] = Object.entries(pl.contents.parameters)
.map(([p, info]) => ({ [p]: info.default }))
.reduce((o, p) => ({ ...o, ...p }), {})
;
newContents.description = this.state.cache.contents.description;
this.setContents(newContents);
}
render = () => {
return (
<div>
<div className='d-flex'>
<Button
className='mx-auto'
outline
color='secondary'
onClick={() => this.props.saveFunc(this.state.cache)}
>
Save Changes (Changes are <ValidSchemaBadge entity='plotterparameter' obj={this.state.cache} />)
</Button>
{/*
<TemplateButton
data={this.state.cache}
entity={'plotter'}
/>
*/}
</div>
<Form>
<FormGroup tag='fieldset'>
<FormGroup>
<Label>Short Description</Label>
<Input
type='text'
id='ppDesc'
placeholder='Parameter description...'
value={this.state.cache.contents.description}
onChange={(e) => this.updateDescription(e.target.value)}
/>
</FormGroup>
<FormGroup>
<Label>Plotter</Label>
<Input
type='select'
className='custom-select'
id='ppPl'
placeholder='Plotter...'
value={this.getPlotter()}
onChange={e => this.updatePlotter(e.target.value)}
>
{
this.props.plotters.map((pl, i) =>
<option key={i} value={pl.name}>{ pl.name }</option>
)
}
</Input>
</FormGroup>
</FormGroup>
</Form>
</div>
);
}
}
const mapStateToProps = (state, ownProps) => {
const obj = {
plotters: Selectors.plotterGet(state),
libraries: Selectors.libraryGet(state),
};
return obj;
};
export default connect(mapStateToProps)(PlotterParameterEditor);
// @flow
import ConnectedPlotterParameterEditor, {PlotterParameterEditor} from './PlotterParameterEditor.jsx';
export {
PlotterParameterEditor,
};
export default ConnectedPlotterParameterEditor;
// @flow
import { jsonClone } from '.';
export type BeatEntity = 'database' | 'library' | 'dataformat' | 'algorithm' | 'toolchain' | 'experiment' | 'plotter';
export type BeatEntity = 'database' | 'library' | 'dataformat' | 'algorithm' | 'toolchain' | 'experiment' | 'plotter' | 'plotterparameter';
export type BeatObject = {|
// name of the object
......@@ -23,6 +23,7 @@ export const BEAT_ENTITIES: BeatEntity[] = [
'toolchain',
'experiment',
'plotter',
'plotterparameter',
];
export const BUILTIN_TYPES = [
......@@ -85,6 +86,8 @@ export const pluralize = (be: BeatEntity): string => {
return 'experiments';
case 'plotter':
return 'plotters';
case 'plotterparameter':
return 'plotterparameters';
default:
throw new Error(`Cannot pluralize invalid BE: "${ be }"`);
}
......@@ -445,7 +448,7 @@ export const getValidPlotterObj = (data: BeatObject = {name: '', contents: {}})
description: '',
language: 'python',
parameters: {},
dataformat: 'plot/unknown/1',
dataformat: '',
uses: {},
...getObj.contents,
}
......@@ -453,3 +456,21 @@ export const getValidPlotterObj = (data: BeatObject = {name: '', contents: {}})
return obj;
};
export const getValidPlotterparameterObj = (data: BeatObject = {name: '', contents: {}}) => {
const getObj = {
name: '',
contents: {},
...jsonClone(data)
};
const obj = {
...getObj,
contents: {
description: '',
...getObj.contents,
}
};
return obj;
};
......@@ -9,11 +9,12 @@ import toolchain from './toolchain.json';
import experiment from './experiment.json';
import execution from './execution.json';
import plotter from './plotter.json';
import plotterparameter from './plotterparameter.json';
import draft04 from 'ajv/lib/refs/json-schema-draft-04.json';
const ajv = new Ajv({ allErrors: true, schemaId: 'id' });
ajv.addMetaSchema(draft04);
ajv.addSchema([common, dataformat, database, library, algorithm, toolchain, experiment, plotter, execution]);
ajv.addSchema([common, dataformat, database, library, algorithm, toolchain, experiment, plotter, plotterparameter, execution]);
export const VALIDATORS = {
dataformat: ajv.compile(dataformat),
......@@ -23,6 +24,7 @@ export const VALIDATORS = {
toolchain: ajv.compile(toolchain),
experiment: ajv.compile(experiment),
plotter: ajv.compile(plotter),
plotterparameter: ajv.compile(plotterparameter),
execution: ajv.compile(execution),
};
Object.freeze(VALIDATORS);
......
{
"$schema": "http://json-schema.org/draft-04/schema#",
"id": "plotterparameter",
"title": "Plotter configurator descriptor",
"description": "This schema defines the properties of an instance of a plot configuration",
"type": "object",
"^[a-zA-Z_][a-zA-Z0-9_-]*/[a-zA-Z0-9_-]+/[0-9]+$": {
"type": ["string", "number", "boolean"]
}
}
......@@ -7,6 +7,7 @@ export type ActionType = 'FETCH_ALL'
| 'SAVE_TOOLCHAIN' | 'ADD_TOOLCHAIN' | 'DELETE_TOOLCHAIN' | 'UPDATE_TOOLCHAIN'
| 'SAVE_EXPERIMENT' | 'ADD_EXPERIMENT' | 'DELETE_EXPERIMENT' | 'UPDATE_EXPERIMENT'
| 'SAVE_PLOTTER' | 'ADD_PLOTTER' | 'DELETE_PLOTTER' | 'UPDATE_PLOTTER'
| 'SAVE_PLOTTERPARAMETER' | 'ADD_PLOTTERPARAMETER' | 'DELETE_PLOTTERPARAMETER' | 'UPDATE_PLOTTERPARAMETER'
| 'SAVE_SETTINGS' | 'UPDATE_SETTINGS'
| 'CLEAR_UNSAVED';
......@@ -47,6 +48,11 @@ export const ADD_PLOTTER: ActionType = 'ADD_PLOTTER';
export const DELETE_PLOTTER: ActionType = 'DELETE_PLOTTER';
export const UPDATE_PLOTTER: ActionType = 'UPDATE_PLOTTER';
export const SAVE_PLOTTERPARAMETER: ActionType = 'SAVE_PLOTTERPARAMETER';
export const ADD_PLOTTERPARAMETER: ActionType = 'ADD_PLOTTERPARAMETER';
export const DELETE_PLOTTERPARAMETER: ActionType = 'DELETE_PLOTTERPARAMETER';
export const UPDATE_PLOTTERPARAMETER: ActionType = 'UPDATE_PLOTTERPARAMETER';
export const SAVE_SETTINGS: ActionType = 'SAVE_SETTINGS';
export const UPDATE_SETTINGS: ActionType = 'UPDATE_SETTINGS';
......
......@@ -28,7 +28,7 @@ export const fetchAllObjects: ActionThunkCreator = () => async (dispatch: Dispat
const jsons = await Promise.all(getFuncs.map(async (get): Promise<*> => get()));
const arrs = jsons.map((j, i, js) => i === js.length - 1 ? j : objToArr(j));
dispatch(settingsSave(arrs[7]));
dispatch(settingsSave(arrs[8]));
dispatch(databaseSave(arrs[0]));
dispatch(librarySave(arrs[1]));
......@@ -37,6 +37,7 @@ export const fetchAllObjects: ActionThunkCreator = () => async (dispatch: Dispat
dispatch(toolchainSave(arrs[4]));
dispatch(experimentSave(arrs[5]));
dispatch(plotterSave(arrs[6]));
dispatch(plotterparameterSave(arrs[7]));
dispatch(clearUnsaved());
};
......@@ -64,6 +65,8 @@ export const deleteObject = (entity: BeatEntity, obj: BeatObject): ActionThunkCr
dispatch(experimentDelete(obj));
case 'plotter':
dispatch(plotterDelete(obj));
case 'plotterparameter':
dispatch(plotterparameterDelete(obj));
break;
}
};
......@@ -96,6 +99,8 @@ export const createObject = (entity: BeatEntity, obj: BeatObject, copiedObjName?
dispatch(experimentAdd(obj));
case 'plotter':
dispatch(plotterAdd(obj));
case 'plotterparameter':
dispatch(plotterparameterAdd(obj));
break;
}
};
......@@ -135,6 +140,11 @@ const plotterAdd: ActionCreator = (obj: BeatObject): Action => ({ type: Types.AD
const plotterDelete: ActionCreator = (obj: BeatObject): Action => ({ type: Types.DELETE_PLOTTER, payload: obj, });
export const plotterUpdate: ActionCreator = (oldName: string, obj: BeatObject): Action => ({ type: Types.UPDATE_PLOTTER, payload: {oldName, obj}, });
export const plotterparameterSave: ActionCreator = (objs: BeatObject[]): Action => ({ type: Types.SAVE_PLOTTERPARAMETER, payload: objs, });
const plotterparameterAdd: ActionCreator = (obj: BeatObject): Action => ({ type: Types.ADD_PLOTTERPARAMETER, payload: obj, });
const plotterparameterDelete: ActionCreator = (obj: BeatObject): Action => ({ type: Types.DELETE_PLOTTERPARAMETER, payload: obj, });
export const plotterparameterUpdate: ActionCreator = (oldName: string, obj: BeatObject): Action => ({ type: Types.UPDATE_PLOTTERPARAMETER, payload: {oldName, obj}, });
export const settingsSave: ActionCreator = (obj: BeatSettings): Action => ({ type: Types.SAVE_SETTINGS, payload: obj, });
export const settingsUpdate: ActionCreator = (obj: BeatSettings): Action => ({ type: Types.UPDATE_SETTINGS, payload: obj, });
......
......@@ -13,6 +13,7 @@ export type State = {|
+toolchain: BeatObject[],
+experiment: BeatObject[],
+plotter: BeatObject[],
+plotterparameter: BeatObject[],
+settings: BeatSettings,
+unsaved: boolean,
|};
......@@ -27,6 +28,7 @@ const initialState: State = {
toolchain: [],
experiment: [],
plotter: [],
plotterparameter: [],
settings: {
prefix: '',
},
......@@ -67,6 +69,7 @@ const algorithm = (state: BeatObject[] = [], action: Action) => action.type.ends
const toolchain = (state: BeatObject[] = [], action: Action) => action.type.endsWith('TOOLCHAIN') ? entityFunc(state, action.type, action.payload) : state;
const experiment = (state: BeatObject[] = [], action: Action) => action.type.endsWith('EXPERIMENT') ? entityFunc(state, action.type, action.payload) : state;
const plotter = (state: BeatObject[] = [], action: Action) => action.type.endsWith('PLOTTER') ? entityFunc(state, action.type, action.payload) : state;
const plotterparameter = (state: BeatObject[] = [], action: Action) => action.type.endsWith('PLOTTERPARAMETER') ? entityFunc(state, action.type, action.payload) : state;
const settings = (state: BeatSettings = {prefix: ''}, action: Action) => {
if(!action.type.endsWith('SETTINGS'))
return state;
......@@ -102,6 +105,7 @@ export default combineReducers({
toolchain,
experiment,
plotter,
plotterparameter,
settings,
unsaved,
});
......@@ -10,6 +10,7 @@ import { getValidAlgorithmObj } from '@helpers/beat';
import { getValidToolchainObj } from '@helpers/beat';
import { getValidExperimentObj } from '@helpers/beat';
import { getValidPlotterObj } from '@helpers/beat';
import { getValidPlotterparameterObj } from '@helpers/beat';
const getObjs = {
database: getValidDatabaseObj,
......@@ -19,6 +20,7 @@ const getObjs = {
toolchain: getValidToolchainObj,
experiment: getValidExperimentObj,
plotter: getValidPlotterObj,
plotterparameter: getValidPlotterparameterObj,
};
export const databaseGet = (state: State) => state.database.map(o => getObjs['database'](o));
......@@ -40,6 +42,7 @@ export const experimentGet = (state: State) => createSelector(
})
)(state);
export const plotterGet = (state: State) => state.plotter.map(o => getObjs['plotter'](o));
export const plotterparameterGet = (state: State) => state.plotterparameter.map(o => getObjs['plotterparameter'](o));
export const settingsGet = (state: State) => state.settings;
export const unsavedGet = (state: State) => state.unsaved;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment