Commit b72d91f5 authored by Jaden's avatar Jaden
Browse files

added basic algorithm editor, need to wire it up to API

parent 8cc78422
This diff is collapsed.
......@@ -4,6 +4,18 @@ import {
Container,
Row,
Col,
Button,
Form,
FormGroup,
Label,
Input,
InputGroup,
FormText,
Collapse,
Card,
CardHeader,
CardBody,
TabContent, TabPane, Nav, NavItem, NavLink, CardTitle, CardText,
} from 'reactstrap';
......@@ -12,28 +24,656 @@ import {
Link
} from 'react-router-dom';
import EntityDetail from './EntityDetail.jsx';
import cn from 'classnames';
import EntityDetail, { mapParamsToData } from './EntityDetail.jsx';
import { objToArr } from './EntityList.jsx';
type Props = {
match: any
match: any,
data: any,
allData: any,
};
const data = {
user: {
test: {
'1': {
name: 'user/test/1'
}
}
}
type State = {
activeTab: string,
cache: any,
dfs: any[],
};
const mapParamsToData = (params) => data[params.user][params.name][params.version];
const orderedParams = (params: any): string[] => [ params.user, params.name, params.version ];
const getDescField = (obj) => obj && obj['#description'] ? '#description' : 'description';
const AlgorithmsDetail = ({ match }: Props) => (
<div>
<EntityDetail instance={mapParamsToData(match.params)} />
</div>
const getValidObj = ({ match, data }: Props) => {
const getObj = {
contents: {},
...JSON.parse(JSON.stringify(mapParamsToData(orderedParams(match.params), data)))
};
return {
name: '',
...getObj,
contents: {
splittable: false,
parameters: {},
uses: {},
groups: [
],
...getObj.contents,
[getDescField(getObj.contents)]: getObj.contents[getDescField(getObj.contents)] || ''
},
};
};
const DeleteInputBtn = ({ deleteFunc }: any) => (
<span className='input-group-btn'>
<Button
color='danger'
onClick={(e) => deleteFunc(e)}
>
X
</Button>
</span>
);
const GroupIOBlock = ({ name, ioObj, dfs, updateFunc, deleteFunc }: any) => (
<FormGroup>
<Row>
<Col sm='6'>
<InputGroup>
<DeleteInputBtn deleteFunc={() => deleteFunc(name)} />
<Input
type='text'
placeholder='Name...'
value={name}
onChange={(e) => updateFunc(name, e.target.value, ioObj)}
/>
</InputGroup>
</Col>
<Col sm='6'>
<Input
type='select'
className='custom-select'
value={ioObj.type || ioObj}
onChange={(e) => updateFunc(name, name, ioObj.type ? { ...ioObj, type: e.target.value } : e.target.value)}
>
<option disabled>Dataformat...</option>
{
dfs.map((d, i) => (
<option key={i} value={d.name}>{d.name}</option>
))
}
</Input>
</Col>
</Row>
</FormGroup>
);
const changeObjFieldName = (obj: {}, oldName: string, newName: string): {} => {
return Object.entries(obj)
.map(([name, val]) => [name === oldName ? newName : name, val])
.reduce((o, [name, val]) => ({...o, [name]: val}), {});
};
const builtinDfs = [
'int8',
'int16',
'int32',
'int64',
'uint8',
'uint16',
'uint32',
'uint64',
'float32',
'float64',
'complex64',
'complex128',
'bool',
'string'
];
const resultDfs = [
'int32',
'float32',
'bool',
'string'
];
class AlgorithmsDetail extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
}
state = {
activeTab: '0',
cache: getValidObj(this.props),
dfs: objToArr(this.props.allData.dataformats) || [],
libs: objToArr(this.props.allData.libraries) || [],
resultDfs: resultDfs.concat((objToArr(this.props.allData.dataformats) || []).filter(d => d.name.startsWith('plot')).map(d => d.name)),
}
tabTo = (tab: string) => { if(this.activeTab !== tab) this.setState({ activeTab: tab }); }
changeContentsVal = (field: string, val: any) => {
this.setState({
cache: {
...this.state.cache,
contents: {
...this.state.cache.contents,
[field]: val
}
}
});
}
updateGroup = (oldGroup: any, newGroup: any) => {
const gIdx = this.state.cache.contents.groups.findIndex(g => JSON.stringify(g) === JSON.stringify(oldGroup));
const newGroups = JSON.parse(JSON.stringify(this.state.cache.contents.groups));
newGroups[gIdx] = newGroup;
this.changeContentsVal('groups', newGroups);
}
updateParameter = (name, param) => {
const ps = this.state.cache.contents.parameters;
ps[name] = param;
this.changeContentsVal('parameters', ps);
}
updateLibrary = (name, lib) => {
const ls = this.state.cache.contents.uses;
ls[name] = lib;
this.changeContentsVal('uses', ls);
}
updateResult = (name, res) => {
const rs = this.state.cache.contents.results;
rs[name] = res;
this.changeContentsVal('results', rs);
}
changeToAnalyzer = () => {
const contents = JSON.parse(JSON.stringify(this.state.cache.contents));
contents.groups = contents.groups.map(g => {
delete g['outputs'];
return g;
});
contents.results = {};
this.setState({
cache: {
...this.state.cache,
contents
}
});
}
changeToNormal = () => {
const contents = JSON.parse(JSON.stringify(this.state.cache.contents));
delete contents.results;
if(contents.groups.length > 0)
contents.groups[0].outputs = {};
this.setState({
cache: {
...this.state.cache,
contents
}
});
}
isAnalyzer = () => { return this.state.cache.contents.results ? true : false; }
descField = () => { return getDescField(this.state.contents); }
deleteIO = (group, type) => (name) => {
delete group[type][name];
this.updateGroup(group, { ...group });
}
render () {
return (
<div>
{ JSON.stringify(this.state.cache) }
<Form>
<FormGroup tag='fieldset'>
<legend>Algorithm Settings</legend>
<FormGroup>
<Label for='algName'>Name</Label>
<Input
type='text'
name='name'
id='algName'
placeholder='New algorithm name...'
value={this.state.cache.name}
onChange={(e) => this.setState({
cache: {
...this.state.cache,
name: e.target.value
}})
}
/>
</FormGroup>
<FormGroup>
<Label for='algDesc'>Short Description</Label>
<Input
type='text'
name='desc'
id='algDesc'
placeholder='Algorithm description...'
value={this.state.cache.contents[this.descField()]}
onChange={(e) => this.changeContentsVal(this.descField(), e.target.value)}
/>
</FormGroup>
<FormGroup check>
<Label check>
<Input
type='checkbox'
checked={this.isAnalyzer()}
onChange={e => e.target.checked ? this.changeToAnalyzer() : this.changeToNormal()}
/>{' '}
Analyser
</Label>
</FormGroup>
<FormGroup check>
<Label check>
<Input
type='checkbox'
checked={this.state.cache.contents.splittable ? true : false}
onChange={e => this.changeContentsVal('splittable', e.target.checked)}
/>{' '}
Splittable
</Label>
</FormGroup>
</FormGroup>
<div className='mt-3 mb-3'>
<Nav tabs>
<NavItem>
<NavLink
className={cn({ active: this.state.activeTab === '0' })}
onClick={() => this.tabTo('0')}
>
Endpoints
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={cn({ active: this.state.activeTab === '1' })}
onClick={() => this.tabTo('1')}
>
Parameters
</NavLink>
</NavItem>
<NavItem>
<NavLink
className={cn({ active: this.state.activeTab === '2' })}
onClick={() => this.tabTo('2')}
>
Libraries
</NavLink>
</NavItem>
{ this.state.cache.contents.results ? (
<NavItem>
<NavLink
className={cn({ active: this.state.activeTab === '3' })}
onClick={() => this.tabTo('3')}
>
Results
</NavLink>
</NavItem>
) : ''
}
</Nav>
<TabContent className='mt-3' activeTab={this.state.activeTab}>
<TabPane tabId='0'> { this.state.cache.contents.groups.map((group, i) => {
const ioUpdate = (subObj: string) => (oldName: string, newName: string, newObj: any) => {
console.log(`changing ${subObj} "${oldName}" -> "${newName}":"${ newObj.type }"`);
const changedObj = changeObjFieldName(group[subObj], oldName, newName);
changedObj[newName] = newObj;
this.updateGroup(group,
{
...group,
[subObj]: changedObj
}
);
};
const inputsUpdate = ioUpdate('inputs');
const outputsUpdate = ioUpdate('outputs');
return (
<Row key={i} className='mb-2'>
<Col sm='12'>
<Card>
<CardHeader>
<InputGroup>
<DeleteInputBtn
deleteFunc={() => this.changeContentsVal(
'groups',
this.state.cache.contents.groups
.filter(g => g.name !== group.name)
)}
/>
<Input
type='text'
placeholder='Group Name...'
value={group.name}
onChange={(e) => this.updateGroup(
group,
{...group, name: e.target.value}
)}
/>
</InputGroup>
</CardHeader>
<CardBody>
<Row> { group.inputs ? (
<Col sm={group.outputs ? '6' : '12'}>
{
Object.entries(group.inputs)
.map(([name, ioObj], i, gEntries) =>
<GroupIOBlock
key={i}
name={name}
ioObj={ioObj}
dfs={this.state.dfs}
updateFunc={inputsUpdate}
deleteFunc={this.deleteIO(group, 'inputs')}
/>
)
}
<Button
outline
block
onClick={(e) => this.updateGroup(
group,
{
...group,
inputs: {
...group.inputs,
[`input ${ Object.keys(group.inputs).length }`]:
{ type: undefined }
}
})
}
>
New Input
</Button>
</Col>
) : '' }
{ group.outputs ? (
<Col sm='6'>
{
Object.entries(group.outputs)
.map(([name, ioObj], i) =>
<GroupIOBlock
key={i}
name={name}
ioObj={ioObj}
dfs={this.state.dfs}
updateFunc={outputsUpdate}
deleteFunc={this.deleteIO(group, 'outputs')}
/>
)
}
<Button outline block
onClick={(e) => this.updateGroup(
group,
{
...group,
outputs: {
...group.outputs,
[`output ${ Object.keys(group.outputs).length }`]:
{ type: undefined }
}
})
}
>New Output</Button>
</Col>
) : '' }
</Row>
</CardBody>
</Card>
</Col>
</Row>
);
})
}
<Button outline block
onClick={(e) => this.changeContentsVal(
'groups',
this.state.cache.contents.groups
.concat([
[
['name', `group ${ this.state.cache.contents.groups.length }`],
['inputs', {}]
].reduce((o, [name, val]) => ({...o, [name]: val}), !this.isAnalyzer() && this.state.cache.contents.groups.length === 0 ? { outputs: {} } : {})
]))
}
>
New Group
</Button>
</TabPane>
<TabPane tabId='1'> { this.state.cache.contents.parameters ? (
Object.entries(this.state.cache.contents.parameters).map(([name, param], i) => (
<Row key={i} className='mb-2'>
<Col sm='12'>
<FormGroup row>
<Col sm='4'>
<InputGroup>
<DeleteInputBtn
deleteFunc={
() => {
const ps = this.state.cache.contents.parameters;
delete ps[name];
this.changeContentsVal('parameters', ps);
}
}
/>
<Input
type='text'
placeholder='Name'
value={name}
onChange={(e) => this.changeContentsVal(
'parameters',
changeObjFieldName(
this.state.cache.contents.parameters,
name,
e.target.value
)
)}
/>
</InputGroup>
</Col>
<Col sm='2'>
<Input
type='select'
className='custom-select'
value={param.type}
onChange={(e) => this.updateParameter(name, {
...param,
type: e.target.value
})}
>
<option disabled>Type</option>
{
builtinDfs.map((d, i) => (
<option key={i} value={d}>{d}</option>
))
}
</Input>
</Col>
<Col sm='2'>
<Input
type='text'
placeholder='Default'
value={param.default}
onChange={(e) => this.updateParameter(name, {
...param,
default: e.target.value
})}
/>
</Col>
<Col>
<Input
type='text'
placeholder='Description'
value={param[name] || param.description || ''}
onChange={(e) => this.updateParameter(name, {
...param,
description: e.target.value
})}
/>
</Col>
</FormGroup>
</Col>
</Row>
))) : ''
}
<Button outline block
onClick={() => this.changeContentsVal('parameters',
{...(this.state.cache.contents.parameters || {}),
[`parameter ${ Object.keys(this.state.cache.contents.parameters || {}).length }`]: {
type: undefined,
default: '',
description: '',