Commit 2e95f4b8 authored by Jaden DIEFENBAUGH's avatar Jaden DIEFENBAUGH

can now create an algorithm from a tc block/analyzer, closes #117

parent 6f34ae53
Pipeline #24954 passed with stages
in 28 minutes and 6 seconds
......@@ -30,7 +30,10 @@ import { connect } from 'react-redux';
import { ContextMenu, MenuItem, ContextMenuTrigger, SubMenu } from 'react-contextmenu';
import { getRandomBrightColor, generateNewKey, copyObj } from '@helpers';
import { getValidToolchainObj as getValidObj } from '@helpers/beat';
import {
getValidToolchainObj as getValidObj,
nameValidator, nameSegmentsForEntity, getTcFromExpName, getValidAlgorithmObj
} from '@helpers/beat';
import type { BeatObject } from '@helpers/beat';
import { fetchLayout, genModuleApiFuncs } from '@helpers/api';
import Validate, { VALIDATORS } from '@helpers/schema';
......@@ -78,6 +81,8 @@ type Props = {
// func to save changes on the current tc
saveFunc: (BeatObject) => any,
updateFunc: (BeatObject) => any,
// creates an algorithm from block data from the ToolchainModal
createAlgorithmFromBlock: (data: NormalBlock | AnalyzerBlock, conns: ConnectionType[]) => any,
};
// represents a timeline of state changes
......@@ -306,6 +311,15 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
this.setState((prevState) => ({ renameGroupModalInfo: val }));
}
closeEditModal = () => {
this.setState({
modalBlockInfo: {
...this.state.modalBlockInfo,
active: false,
}
});
}
/* GROUPS */
// renames a group from an old name to a new one
......@@ -904,6 +918,22 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
};
}
createAlgorithmFromBlock = async (algName: string) => {
const {active, name, set} = this.state.modalBlockInfo;
const data = this.props.data.contents[set].find(b => b.name === name);
if(!data){
console.error(`cannot find ${ name } to create ${ algName } in blocks or analyzers`);
return;
}
const conns = this.props.data.contents.connections
.filter(c => c.to.startsWith(`${ name }.`))
;
await this.props.createAlgorithmFromBlock({ ...data, name: algName }, conns);
}
/* CONTEXT MENUS */
svgContextMenuLocation: ?[number, number] = undefined
......@@ -1309,18 +1339,12 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
<EditModal
data={this.props.data.contents[set].find(d => d.name === name)}
active={active}
toggle={() => {
this.setState({
modalBlockInfo: {
...this.state.modalBlockInfo,
active: false,
}
});
}}
toggle={() => this.closeEditModal()}
blockNames={Object.keys(this.props.data.contents.representation.blocks) || []}
deleteBlock={() => this.deleteBlocks([name])}
possibleChannels={possibleChannels}
updateBlockData={this.updateBlockData}
createAlgorithmFromBlock={this.createAlgorithmFromBlock}
/>
);
}
......@@ -1422,6 +1446,50 @@ const mapDispatchToProps = (dispatch, ownProps) => ({
console.log(`dispatching for ${ obj.name }`);
dispatch(Actions[`toolchainUpdate`](obj.name, obj));
},
createAlgorithmFromBlock: async (data: NormalBlock | AnalyzerBlock, conns: ConnectionType[]) => {
let newObj = getValidAlgorithmObj({ name: data.name, contents: {} });
// generate the alg obj
// first, separate into groups
// look at all connections to block, each different channel is a different group
// put the inputs in the corresponding groups as well
const inputGroups = conns.reduce((groups, c) => {
const input = c.to.split('.')[1];
const channel: string = c.channel;
if(Array.isArray(groups[channel])){
groups[channel].push(input);
} else {
groups[channel] = [input];
}
return groups;
}, {});
// coverts a list of input names to the format needed for algorithm groups
const groupListToObj = (iList: string[]): {[string]: any} =>
iList.reduce((o, i) => ({...o, [i]: { type: '' }}), {});
// generate group objs from the inputs split between groups
newObj.contents.groups = Object.entries(inputGroups)
.map(([gName, inputs], i) => ({ name: gName, inputs: groupListToObj(inputs) }) );
// is normal block
if(Array.isArray(data.outputs)){
// all block outputs only go to first group
if(Array.isArray(data.outputs) && newObj.contents.groups.length > 0){
newObj.contents.groups[0].outputs = groupListToObj(data.outputs);
}
}
// is analyzer block
else {
// make it an analyzer
delete newObj.contents['splittable'];
newObj.contents.results = {};
}
console.log(newObj);
await dispatch(Actions.createObject('algorithm', newObj)());
}
});
export default connect(mapStateToProps, mapDispatchToProps)(ToolchainEditor);
......@@ -363,7 +363,7 @@ describe('<ToolchainEditor />', function() {
expect(wrapper.find('.modal').find('CacheInput#tcModalInitFocus').props().value).to.equal('block');
wrapper.find('.modal').find('CacheInput#tcModalInitFocus').prop('onChange')( { target: { value: 'training_alg' }});
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
wrapper.find('.modal button.btn-secondary').at(1).simulate('click');
wrapper.update();
/*
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
......@@ -399,7 +399,7 @@ describe('<ToolchainEditor />', function() {
expect(wrapper.find('.modal').find('CacheInput#tcModalInitFocus').props().value).to.equal('block0');
wrapper.find('.modal').find('CacheInput#tcModalInitFocus').prop('onChange')( { target: { value: 'testing_alg' }});
wrapper.update();
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
wrapper.find('.modal button.btn-secondary').at(1).simulate('click');
wrapper.update();
/*
wrapper.find('.modal button.btn-secondary').at(0).simulate('click');
......@@ -437,7 +437,7 @@ describe('<ToolchainEditor />', function() {
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.update();
*/
wrapper.find('.modal button.btn-secondary').simulate('click');
wrapper.find('.modal button.btn-secondary').at(1).simulate('click');
wrapper.update();
wrapper.find('.modal CacheInput[value="input"]').prop('onChange')( { target: { value: 'scores' }});
wrapper.update();
......
......@@ -12,7 +12,7 @@ const fetchConfig = {
let port = '5000';
const toUrl = (str) => `http://127.0.0.1:${ port }/${ str }`;
export const toUrl = (str: string) => `http://127.0.0.1:${ port }/${ str }`;
// curried func for calling the REST API
// basically:
......
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