An easy-to-use platform for EEG experimentation in the classroom
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fixed more errors; refactoring becoming clear

+51 -29
+3 -2
app/components/CollectComponent/ConnectModal.tsx
··· 1 1 import { Observable } from 'rxjs'; 2 2 import React, { Component } from 'react'; 3 3 import { isNil, debounce } from 'lodash'; 4 + import { History } from 'history'; 4 5 import { Modal, Button, Segment, List, Grid, Divider } from 'semantic-ui-react'; 5 6 import { 6 7 DEVICES, ··· 9 10 SCREENS, 10 11 } from '../../constants/constants'; 11 12 import styles from '../styles/collect.css'; 12 - import { SignalQualityData } from '../../constants/interfaces'; 13 + import { SignalQualityData, PipesEpoch } from '../../constants/interfaces'; 13 14 import { DeviceActions } from '../../actions'; 14 15 15 16 interface Props { ··· 17 18 open: boolean; 18 19 onClose: () => void; 19 20 connectedDevice: Record<string, any>; 20 - signalQualityObservable?: Observable<SignalQualityData>; 21 + signalQualityObservable?: Observable<PipesEpoch>; 21 22 deviceType: DEVICES; 22 23 deviceAvailability: DEVICE_AVAILABILITY; 23 24 connectionStatus: CONNECTION_STATUS;
+18 -10
app/components/DesignComponent/StimuliDesignColumn.tsx
··· 4 4 import { Form, Button, Table, Icon } from 'semantic-ui-react'; 5 5 import { toast } from 'react-toastify'; 6 6 import * as path from 'path'; 7 + import { isString } from 'lodash'; 7 8 import { readImages } from '../../utils/filesystem/storage'; 8 9 import { loadFromSystemDialog } from '../../utils/filesystem/select'; 9 10 import { FILE_TYPES } from '../../constants/constants'; ··· 14 15 title: string; 15 16 response: string; 16 17 dir: string; 17 - onChange: (arg0: string, arg1: string) => void; 18 + numberImages?: number; 19 + onChange: (arg0: string, arg1: string, arg2: string) => void; 20 + } 21 + 22 + interface State { 23 + numberImages?: number; 18 24 } 19 25 20 26 const RESPONSE_OPTIONS = new Array(10).fill(0).map((_, i) => ({ ··· 23 29 value: i.toString(), 24 30 })); 25 31 26 - export default class StimuliDesignColumn extends Component<Props> { 32 + export default class StimuliDesignColumn extends Component<Props, State> { 27 33 constructor(props: Props) { 28 34 super(props); 29 35 this.handleSelectFolder = this.handleSelectFolder.bind(this); ··· 46 52 47 53 async handleSelectFolder() { 48 54 const dir = await loadFromSystemDialog(FILE_TYPES.STIMULUS_DIR); 49 - if (dir) { 55 + if (dir && isString(dir)) { 50 56 const images = readImages(dir); 51 57 if (images.length < 1) { 52 58 toast.error('No images in folder!'); ··· 90 96 fluid 91 97 selection 92 98 value={this.props.response} 93 - onChange={(event, data) => 94 - this.props.onChange( 95 - 'response', 96 - data.value, 97 - `stimulus${this.props.num}` 98 - ) 99 - } 99 + onChange={(event, data) => { 100 + if (data.value && isString(data.value)) { 101 + this.props.onChange( 102 + 'response', 103 + data.value, 104 + `stimulus${this.props.num}` 105 + ); 106 + } 107 + }} 100 108 placeholder="Select" 101 109 options={RESPONSE_OPTIONS} 102 110 />
+3 -1
app/components/EEGExplorationComponent.tsx
··· 7 7 Image, 8 8 Divider, 9 9 } from 'semantic-ui-react'; 10 + import { Observable } from 'rxjs'; 10 11 import { History } from 'history'; 11 12 import { 12 13 PLOTTING_INTERVAL, ··· 20 21 import ConnectModal from './CollectComponent/ConnectModal'; 21 22 import styles from './styles/common.css'; 22 23 import { DeviceActions } from '../actions'; 24 + import { SignalQualityData, PipesEpoch } from '../constants/interfaces'; 23 25 24 26 interface Props { 25 27 history: History; 26 28 connectedDevice: Record<string, any>; 27 - signalQualityObservable: any | null | undefined; 29 + signalQualityObservable: Observable<PipesEpoch>; 28 30 deviceType: DEVICES; 29 31 deviceAvailability: DEVICE_AVAILABILITY; 30 32 connectionStatus: CONNECTION_STATUS;
+19 -9
app/components/HomeComponent/OverviewComponent.tsx
··· 8 8 import PreviewButton from '../PreviewButtonComponent'; 9 9 import { loadProtocol } from '../../utils/labjs/functions'; 10 10 11 - const OVERVIEW_STEPS = { 12 - OVERVIEW: 'OVERVIEW', 13 - BACKGROUND: 'BACKGROUND', 14 - PROTOCOL: 'PROTOCOL', 15 - }; 11 + enum OVERVIEW_STEPS { 12 + OVERVIEW = 'OVERVIEW', 13 + BACKGROUND = 'BACKGROUND', 14 + PROTOCOL = 'PROTOCOL', 15 + } 16 16 17 17 interface Props { 18 18 type: EXPERIMENTS; 19 + protocol: string; 20 + background: string; 21 + background_title: string; 22 + overview: string; 19 23 onStartExperiment: (arg0: EXPERIMENTS) => void; 20 24 onCloseOverview: () => void; 21 25 } ··· 38 42 } 39 43 40 44 handleStepClick(step: string) { 41 - this.setState({ activeStep: step }); 45 + if (isEnum(OVERVIEW_STEPS)(step)) { 46 + this.setState({ activeStep: step }); 47 + } 42 48 } 43 49 44 50 handlePreview(e) { ··· 66 72 className={styles.previewWindow} 67 73 > 68 74 <PreviewExperimentComponent 69 - {...loadProtocol(this.props.paradigm)} 75 + {...loadProtocol(this.props.type)} 70 76 isPreviewing={this.state.isPreviewing} 71 77 onEnd={this.endPreview} 72 78 type={this.props.type} 73 - paradigm={this.props.paradigm} 74 79 /> 75 80 </Grid.Column> 76 81 <Grid.Column stretched width={4} verticalAlign="middle"> ··· 141 146 steps={OVERVIEW_STEPS} 142 147 activeStep={this.state.activeStep} 143 148 onStepClick={this.handleStepClick} 144 - button={ 149 + saveButton={ 145 150 <Button 146 151 primary 147 152 onClick={() => this.props.onStartExperiment(this.props.type)} ··· 157 162 ); 158 163 } 159 164 } 165 + 166 + // Generic curreid enum type guard 167 + function isEnum<T>(en: T) { 168 + return (val: any): val is T[keyof T] => val in Object.values(en); 169 + }
-2
app/components/HomeComponent/index.tsx
··· 112 112 this.props.ExperimentActions.CreateNewWorkspace({ 113 113 title: experimentType, 114 114 type: experimentType, 115 - paradigm: experimentType, 116 115 }); 117 116 this.props.history.push(SCREENS.DESIGN.route); 118 117 } ··· 132 131 this.props.ExperimentActions.CreateNewWorkspace({ 133 132 title, 134 133 type: EXPERIMENTS.CUSTOM, 135 - paradigm: EXPERIMENTS.CUSTOM, 136 134 }); 137 135 this.props.history.push(SCREENS.DESIGN.route); 138 136 }
+1 -1
app/components/PreviewButtonComponent.tsx
··· 1 1 import React, { PureComponent } from 'react'; 2 - import { Button } from 'semantic-ui-react'; 2 + import { Button, ButtonProps } from 'semantic-ui-react'; 3 3 4 4 interface Props { 5 5 isPreviewing: boolean;
+5 -4
app/components/SignalQualityIndicatorComponent.tsx
··· 2 2 import { isNil } from 'lodash'; 3 3 import { Segment } from 'semantic-ui-react'; 4 4 import * as d3 from 'd3'; 5 - import { Observable } from 'rxjs'; 5 + import { Observable, Subscription } from 'rxjs'; 6 6 import SignalQualityIndicatorSVG from './svgs/SignalQualityIndicatorSVG'; 7 + import { PipesEpoch } from '../constants/interfaces'; 7 8 8 9 interface Props { 9 - signalQualityObservable: Observable | null | undefined; 10 - plottingInterval: number | null | undefined; 10 + signalQualityObservable: Observable<PipesEpoch>; 11 + plottingInterval: number; 11 12 } 12 13 13 14 class SignalQualityIndicatorComponent extends Component<Props> { 14 - // signalQualitySubscription: Subscription; 15 + signalQualitySubscription: Subscription | null; 15 16 16 17 constructor(props: Props) { 17 18 super(props);
+1
app/epics/deviceEpics.ts
··· 159 159 map(() => DeviceActions.SetConnectionStatus(CONNECTION_STATUS.CONNECTING)) 160 160 ); 161 161 162 + // TODO: confirm the shape of data that actually flows through these observables and formalize with interfaces 162 163 const setRawObservableEpic: Epic< 163 164 DeviceActionType, 164 165 DeviceActionType,
+1
app/utils/labjs/functions.ts
··· 7 7 import { buildCustomTimeline } from './protocols/custom'; 8 8 9 9 // loads a protocol of the experiment 10 + // TODOL refactor this experiment description system to be much more predictable 10 11 export const loadProtocol = (paradigm: EXPERIMENTS) => { 11 12 let protocol; 12 13 switch (paradigm) {