diff --git a/conda/js/package-lock.json b/conda/js/package-lock.json index 368b8a9d828a657570a02bbf845864853f1f462a..660710ce44b23482ce3b39cbc032af4a221b00ed 100644 --- a/conda/js/package-lock.json +++ b/conda/js/package-lock.json @@ -2524,12 +2524,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2544,17 +2546,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -2671,7 +2676,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -2683,6 +2689,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2697,6 +2704,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2808,7 +2816,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -2941,6 +2950,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/conda/js/src/components/algorithm/AlgorithmEditor.jsx b/conda/js/src/components/algorithm/AlgorithmEditor.jsx index 17f5cf7255ba6dab0524361cb8127aeeca79f231..7b5845c3ec0c3af7a5fdceaaa871171f3e60d7a0 100644 --- a/conda/js/src/components/algorithm/AlgorithmEditor.jsx +++ b/conda/js/src/components/algorithm/AlgorithmEditor.jsx @@ -228,26 +228,11 @@ export class AlgorithmEditor extends React.Component<Props, State> { <Row key={i} className='mb-2' id={`endpoint${ i }`}> <Col sm='12'> <Card> - <CardHeader> - <CacheInput - type='text' - placeholder='Group Name...' - value={group.name} - onChange={(e) => this.updateGroup( - group, - {...group, name: e.target.value} - )} - validateFunc={str => !groups.map(g => [0]).includes(str) || <span>Each group name must be unique</span>} - > - <DeleteInputBtn - deleteFunc={() => this.changeContentsVal( - 'groups', - groups - .filter(g => g.name !== group.name) - )} - /> - </CacheInput> - </CardHeader> + { groups.length > 1 && + <CardHeader> + Group { i } + </CardHeader> + } <CardBody> { Object.keys(group.inputs).length === 0 && i !== 0 && <Alert color='warning'> @@ -339,13 +324,24 @@ export class AlgorithmEditor extends React.Component<Props, State> { )} </Row> </CardBody> + { i !== 0 && + <Button block color='danger' outline + onClick={() => this.changeContentsVal( + 'groups', + groups + .filter(g => g.name !== group.name) + )} + > + Delete Group + </Button> + } </Card> </Col> </Row> ); }) } - <Button outline block + <Button block id='newGroupBtn' onClick={(e) => { const newGroupName = generateNewKey('group', this.props.data.contents.groups.map(g => g.name)); diff --git a/conda/js/src/components/algorithm/AlgorithmEditor.spec.jsx b/conda/js/src/components/algorithm/AlgorithmEditor.spec.jsx index 98045c2cccc2e2c9611995fb11d9606b2caf80ab..446093add5cfd621312af4302d281a43d781f6c9 100644 --- a/conda/js/src/components/algorithm/AlgorithmEditor.spec.jsx +++ b/conda/js/src/components/algorithm/AlgorithmEditor.spec.jsx @@ -115,31 +115,28 @@ describe('<AlgorithmEditor />', () => { expect(updateFunc.callCount).to.equal(1); expect(wrapper.props().data.contents).to.have.property('splittable', true); - wrapper.find('button#newGroupBtn').simulate('click'); - expect(updateFunc.callCount).to.equal(2); + expect(updateFunc.callCount).to.equal(1); expect(wrapper.props().data.contents).to.have.property('groups').with.lengthOf(1); expect(wrapper.props().data.contents.groups[0]).to.have.property('inputs'); expect(wrapper.props().data.contents.groups[0]).to.have.property('outputs'); - wrapper.find('CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: 'main' }}); - expect(updateFunc.callCount).to.equal(3); - expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'main'); + expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'group'); wrapper.find('button#newInputBtn').simulate('click'); - expect(updateFunc.callCount).to.equal(4); + expect(updateFunc.callCount).to.equal(2); wrapper.find('button#newOutputBtn').simulate('click'); - expect(updateFunc.callCount).to.equal(5); + expect(updateFunc.callCount).to.equal(3); wrapper.find('.algInput').find('CacheInput').prop('onChange')( { target: { value: 'in_data' }}); - expect(updateFunc.callCount).to.equal(6); + expect(updateFunc.callCount).to.equal(4); wrapper.find('.algOutput').find('CacheInput').prop('onChange')( { target: { value: 'out_data' }}); - expect(updateFunc.callCount).to.equal(7); + expect(updateFunc.callCount).to.equal(5); const ioType = 'system/integer/1'; wrapper.find('.algInput select').prop('onChange')( { target: { value: ioType }}); - expect(updateFunc.callCount).to.equal(8); + expect(updateFunc.callCount).to.equal(6); wrapper.find('.algOutput select').prop('onChange')( { target: { value: ioType }}); - expect(updateFunc.callCount).to.equal(9); + expect(updateFunc.callCount).to.equal(7); expect(wrapper.props().data.contents.groups[0].inputs).to.have.deep.property('in_data', { type: ioType }); expect(wrapper.props().data.contents.groups[0].outputs).to.have.deep.property('out_data', { type: ioType }); @@ -153,7 +150,7 @@ describe('<AlgorithmEditor />', () => { 'type': 'system/integer/1' } }, - 'name': 'main', + 'name': 'group', 'outputs': { 'out_data': { 'type': 'system/integer/1' @@ -195,13 +192,11 @@ describe('<AlgorithmEditor />', () => { wrapper.find('#algSplittable input').prop('onChange')( { target: { checked: true }}); expect(wrapper.props().data.contents).to.have.property('splittable', true); - wrapper.find('button#newGroupBtn').simulate('click'); expect(wrapper.props().data.contents).to.have.property('groups').with.lengthOf(1); expect(wrapper.props().data.contents.groups[0]).to.have.property('inputs'); expect(wrapper.props().data.contents.groups[0]).to.have.property('outputs'); - wrapper.find('CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: 'main' }}); - expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'main'); + expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'group'); wrapper.find('button#newInputBtn').simulate('click'); wrapper.find('button#newOutputBtn').simulate('click'); @@ -260,7 +255,7 @@ describe('<AlgorithmEditor />', () => { 'type': 'system/integer/1' } }, - 'name': 'main', + 'name': 'group', 'outputs': { 'out_data': { 'type': 'system/integer/1' @@ -310,13 +305,11 @@ describe('<AlgorithmEditor />', () => { wrapper.find('#algAnalyzer input').prop('onChange')( { target: { checked: true }}); expect(wrapper.props().data.contents).to.have.property('results'); - wrapper.find('button#newGroupBtn').simulate('click'); expect(wrapper.props().data.contents).to.have.property('groups').with.lengthOf(1); expect(wrapper.props().data.contents.groups[0]).to.have.property('inputs'); expect(wrapper.props().data.contents.groups[0]).to.not.have.property('outputs'); - wrapper.find('CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: 'main' }}); - expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'main'); + expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'group'); wrapper.find('button#newInputBtn').simulate('click'); @@ -380,7 +373,7 @@ describe('<AlgorithmEditor />', () => { 'type': 'system/integer/1' } }, - 'name': 'main' + 'name': 'group' } ], parameters: {}, @@ -434,7 +427,6 @@ describe('<AlgorithmEditor />', () => { wrapper.find('#algSplittable input').prop('onChange')( { target: { checked: true }}); expect(wrapper.props().data.contents).to.have.property('splittable', true); - wrapper.find('button#newGroupBtn').simulate('click'); wrapper.find('button#newGroupBtn').simulate('click'); expect(wrapper.props().data.contents).to.have.property('groups').with.lengthOf(2); @@ -444,8 +436,7 @@ describe('<AlgorithmEditor />', () => { expect(wrapper.props().data.contents.groups[1]).to.not.have.property('outputs'); // Group 1 - wrapper.find('#endpoint0 CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: 'main' }}); - expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'main'); + expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'group'); wrapper.find('#endpoint0 button#newInputBtn').simulate('click'); wrapper.find('#endpoint0 button#newOutputBtn').simulate('click'); @@ -461,8 +452,7 @@ describe('<AlgorithmEditor />', () => { expect(wrapper.props().data.contents.groups[0].outputs).to.have.deep.property('out_data', { type: ioType }); // Group 2 - wrapper.find('#endpoint1 CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: 'sub' }}); - expect(wrapper.props().data.contents.groups[1]).to.have.property('name', 'sub'); + expect(wrapper.props().data.contents.groups[1]).to.have.property('name', 'group0'); wrapper.find('#endpoint1 button#newInputBtn').simulate('click'); @@ -479,7 +469,7 @@ describe('<AlgorithmEditor />', () => { 'type': 'system/integer/1' } }, - 'name': 'main', + 'name': 'group', 'outputs': { 'out_data': { 'type': 'system/integer/1' @@ -492,7 +482,7 @@ describe('<AlgorithmEditor />', () => { 'type': 'system/integer/1' } }, - 'name': 'sub' + 'name': 'group0' } ], parameters: {}, @@ -529,13 +519,11 @@ describe('<AlgorithmEditor />', () => { wrapper.find('#algSplittable input').prop('onChange')( { target: { checked: true }}); expect(wrapper.props().data.contents).to.have.property('splittable', true); - wrapper.find('button#newGroupBtn').simulate('click'); expect(wrapper.props().data.contents).to.have.property('groups').with.lengthOf(1); expect(wrapper.props().data.contents.groups[0]).to.have.property('inputs'); expect(wrapper.props().data.contents.groups[0]).to.have.property('outputs'); - wrapper.find('CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: 'main' }}); - expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'main'); + expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'group'); wrapper.find('button#newInputBtn').simulate('click'); wrapper.find('button#newOutputBtn').simulate('click'); @@ -578,7 +566,7 @@ describe('<AlgorithmEditor />', () => { 'splittable': true, 'groups': [ { - 'name': 'main', + 'name': 'group', 'inputs': { 'in_data': { 'type': 'system/integer/1' @@ -628,13 +616,11 @@ describe('<AlgorithmEditor />', () => { wrapper.find('#algAnalyzer input').prop('onChange')( { target: { checked: true }}); expect(wrapper.props().data.contents).to.have.property('results'); - wrapper.find('button#newGroupBtn').simulate('click'); expect(wrapper.props().data.contents).to.have.property('groups').with.lengthOf(1); expect(wrapper.props().data.contents.groups[0]).to.have.property('inputs'); expect(wrapper.props().data.contents.groups[0]).to.not.have.property('outputs'); - wrapper.find('CacheInput[placeholder="Group Name..."]').prop('onChange')( { target: { value: '' }}); - expect(wrapper.props().data.contents.groups[0]).to.have.property('name', ''); + expect(wrapper.props().data.contents.groups[0]).to.have.property('name', 'group'); wrapper.find('button#newInputBtn').simulate('click'); @@ -680,7 +666,7 @@ describe('<AlgorithmEditor />', () => { 'language': 'python', 'groups': [ { - name: '', + name: 'group', 'inputs': { 'in_data': { 'type': 'system/integer/1' diff --git a/conda/js/src/helpers/beat.js b/conda/js/src/helpers/beat.js index 3ab88b3eacd5033c3922011c1e708a13cdcd31be..c0c804b51539518bc46f7342fb50c4c9f6c03134 100644 --- a/conda/js/src/helpers/beat.js +++ b/conda/js/src/helpers/beat.js @@ -267,6 +267,11 @@ export const getValidAlgorithmObj = (data: BeatObject = {name: '', contents: {}} parameters: {}, uses: {}, groups: [ + { + name: 'group', + inputs: {}, + outputs: {}, + } ], description: '', language: 'python',