Commit cb3e7928 authored by Jaden DIEFENBAUGH's avatar Jaden DIEFENBAUGH

[js][db] added basic protocol template insertion support, #74

parent 1665fe34
......@@ -19,7 +19,7 @@ import {
FormFeedback,
Alert,
InputGroupAddon,
UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem,
Dropdown, UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem,
ButtonGroup,
ListGroup, ListGroupItem,
UncontrolledTooltip,
......@@ -32,6 +32,7 @@ import './DatabaseEditor.css';
import { changeObjFieldName, copyObj } from '@helpers';
import { getValidDatabaseObj as getValidObj } from '@helpers/beat';
import type { BeatObject } from '@helpers/beat';
import fuse from 'fuse.js';
import * as Selectors from '@store/selectors.js';
......@@ -50,10 +51,23 @@ type Props = {
databases: BeatObject[],
dataformats: BeatObject[],
updateFunc: (BeatObject) => any,
protocols: SelectorProtocol[]
};
export type Protocol = {
name: string,
template: string,
sets: Set[],
};
// the protocols from the databaseProtocols selector has an additional field
// that's not in the protocols in database objects
type SelectorProtocol = Protocol & { database: string };
type State = {
activeProtocol: number,
insertProtocolOpen: boolean,
searchResults: SelectorProtocol[],
};
export type Set = {
......@@ -68,12 +82,17 @@ export type Set = {
},
};
export type Protocol = {
name: string,
template: string,
sets: Set[],
const FuseOptions = {
shouldSort: true,
tokenize: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: ['template'],
};
let Fuse;
export class DatabaseEditor extends React.Component<Props, State> {
constructor(props: Props) {
......@@ -82,6 +101,8 @@ export class DatabaseEditor extends React.Component<Props, State> {
state = {
activeProtocol: 0,
insertProtocolOpen: false,
searchResults: [],
}
setContents = (newContents: any) => {
......@@ -94,6 +115,21 @@ export class DatabaseEditor extends React.Component<Props, State> {
});
}
componentDidMount = () => {
this.updateFuseInstance();
}
componentDidUpdate = (prevProps: Props, prevState: State) => {
this.updateFuseInstance(prevProps);
}
updateFuseInstance = (prevProps?: Props) => {
// update fuse & reset results if search data changed
if(!prevProps || this.props.protocols !== prevProps.protocols){
Fuse = new fuse(this.props.protocols, FuseOptions);
}
}
activateProtocol = (index: number) => {
this.setState({ activeProtocol: index });
}
......@@ -116,6 +152,18 @@ export class DatabaseEditor extends React.Component<Props, State> {
);
}
toggleInsertProtocol = (val: boolean = !this.state.insertProtocolOpen) => {
this.setState({ insertProtocolOpen: val });
};
protocolSearch = (str: string) => {
const res = Fuse.search(str);
this.setState(prevState => ({
searchResults: res.slice(0, 5),
insertProtocolOpen: res.length > 0,
}));
};
renderProtocol = (index: number, protocol: Protocol) => (
<Container className='protocol'>
<FormGroup row>
......@@ -604,28 +652,74 @@ export class DatabaseEditor extends React.Component<Props, State> {
>
Clone
</Button>
</ButtonGroup>
<Button
className='ml-3'
color='success'
id='newProtocol'
onClick={e => {
const protocols = [...this.props.data.contents.protocols, {
name: '',
template: '',
sets: [],
}];
<Button
outline
color='success'
id='newProtocol'
onClick={e => {
const protocols = [...this.props.data.contents.protocols, {
name: '',
template: '',
sets: [],
}];
this.setContents({
...this.props.data.contents,
protocols
});
this.setContents({
...this.props.data.contents,
protocols
});
this.activateProtocol(protocols.length - 1);
}}
this.activateProtocol(protocols.length - 1);
}}
>
Create
</Button>
</ButtonGroup>
<Dropdown
isOpen={this.state.insertProtocolOpen}
toggle={e => this.toggleInsertProtocol(false)}
style={{flex: 1}}
className='ml-2 mr-2'
>
+
</Button>
<DropdownToggle
tag='span'
>
<Input
onChange={e => {
this.protocolSearch(e.target.value);
}}
placeholder={`Insert protocol from template...`}
title={`You may insert a protocol from a template from any database`}
/>
</DropdownToggle>
<DropdownMenu>
{
this.state.searchResults.map((r, i) =>
<DropdownItem
tag={Button}
key={i}
onClick={e => {
const newProtocol = copyObj(r);
delete newProtocol['database'];
const newProtocols = [...this.props.data.contents.protocols, newProtocol];
this.setContents({
...this.props.data.contents,
protocols: newProtocols,
});
this.activateProtocol(newProtocols.length - 1);
}}
>
{ `${ r.template } (${ r.database })` }
{' '}
<small className='text-muted'>
Sets: { r.sets.length }
</small>
</DropdownItem>
)
}
</DropdownMenu>
</Dropdown>
</div>
{ protocol && this.renderProtocol(
protocolIdx,
......@@ -805,7 +899,8 @@ const mapStateToProps = (state, ownProps) => {
const obj = {
databases: dbs,
dataformats: Selectors.dataformatGet(state),
data: dbs[ownProps.index] || getValidObj()
data: dbs[ownProps.index] || getValidObj(),
protocols: Selectors.databaseProtocols(state),
};
return obj;
};
......
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