@@ -5,191 +5,41 @@ import { reduxForm } from 'redux-form';
55import ReactTabs from 'react-tabs' ;
66
77import { FormComponent , Form , TextInput , TextareaInput , SubmitButton ,
8- CheckBoxInput , SelectInput } from './Form' ;
8+ CheckBoxInput , SelectInput } from './Form' ;
99import * as Validate from '../validate' ;
1010import Expand from './Expand' ;
1111import * as Action from '../actions' ;
1212import Plot from './Plot' ;
1313import FoldableRow from './FoldableRow' ;
1414import { reformatDatetime , contains } from '../utils' ;
15- import Delete from './Delete' ;
16- import Download from './Download' ;
17-
18- const { Tab, Tabs, TabList, TabPanel } = { ...ReactTabs } ;
19-
20-
21- let FeaturizeForm = ( props ) => {
22- const { fields, fields : { datasetID, featuresetName, customFeatsCode } ,
23- handleSubmit, submitting, resetForm, error, featuresList,
24- featureDescriptions } = props ;
25- const datasets = props . datasets . map ( ds => (
26- { id : ds . id ,
27- label : ds . name }
28- ) ) ;
29-
30- return (
31- < div >
32- < Form onSubmit = { handleSubmit } error = { error } >
33- < SubmitButton
34- label = "Compute Selected Features"
35- submiting = { submitting }
36- resetForm = { resetForm }
37- />
38- < TextInput label = "Feature Set Name" { ...featuresetName } />
39- < SelectInput
40- label = "Select Dataset to Featurize"
41- key = { props . selectedProject . id }
42- options = { datasets }
43- { ...datasetID }
44- />
45- < b > Select Features to Compute</ b > < br />
46- < Expand label = "Filter By Tag" id = "featureTagsExpander" >
47- < span > < i > Features associated with at least one checked tag will be shown below</ i > </ span >
48- {
49- props . tagList . map ( tag => (
50- < CheckBoxInput
51- defaultChecked
52- key = { tag }
53- label = { tag }
54- divStyle = { { display : "table-cell" , width : "150px" } }
55- onChange = { ( ) => { props . dispatch ( Action . clickFeatureTagCheckbox ( tag ) ) ; } }
56- />
57- ) )
58- }
59- </ Expand >
60- < Tabs >
61- < TabList >
62- {
63- Object . keys ( props . featuresByCategory ) . map ( ( ctgy , idx ) => (
64- < Tab key = { idx } > { ctgy } </ Tab >
65- ) )
66- }
67- < Tab > Custom Features</ Tab >
68- </ TabList >
69- {
70- Object . keys ( props . featuresByCategory ) . map ( ( ctgy , idx ) => (
71- < TabPanel key = { idx } >
72- < a
73- href = "#"
74- onClick = { ( ) => {
75- props . dispatch ( Action . groupToggleCheckedFeatures (
76- props . featuresByCategory [ ctgy ]
77- ) ) ;
78- } }
79- >
80- Check/Uncheck All
81- </ a >
82- < table style = { { overflow : "auto" } } >
83- < tbody >
84- {
85- props . featuresByCategory [ ctgy ] . filter ( feat => (
86- contains ( featuresList , feat )
87- ) ) . map ( ( feature , idx2 ) => (
88- < tr key = { idx2 } style = { idx2 % 2 == 0 ? { backgroundColor : "#f2f2f2" } : { } } >
89- < td style = { { paddingLeft : "20px" } } >
90- < CheckBoxInput
91- key = { feature }
92- label = { feature }
93- { ...fields [ feature ] }
94- />
95- </ td >
96- < td style = { { paddingLeft : "5px" , verticalAlign : "bottom" } } >
97- { featureDescriptions [ feature ] }
98- </ td >
99- </ tr >
100- ) )
101- }
102- </ tbody >
103- </ table >
104- </ TabPanel >
105- ) )
106- }
107- < TabPanel >
108- < TextareaInput
109- label = "Enter Python code defining custom features"
110- rows = "10"
111- cols = "50"
112- { ...customFeatsCode }
113- />
114- </ TabPanel >
115- </ Tabs >
116- </ Form >
117- </ div >
118- ) ;
119- } ;
120- FeaturizeForm . propTypes = {
121- fields : PropTypes . object . isRequired ,
122- datasets : PropTypes . arrayOf ( PropTypes . object ) . isRequired ,
123- error : PropTypes . string ,
124- handleSubmit : PropTypes . func . isRequired ,
125- submitting : PropTypes . bool . isRequired ,
126- resetForm : PropTypes . func . isRequired ,
127- selectedProject : PropTypes . object ,
128- featuresByCategory : PropTypes . object ,
129- tagList : PropTypes . arrayOf ( PropTypes . string ) . isRequired ,
130- featuresList : PropTypes . array ,
131- featureDescriptions : PropTypes . object
132- } ;
133- FeaturizeForm . defaultProps = {
134- error : "" ,
135- selectedProject : { } ,
136- featuresByCategory : { } ,
137- featuresList : [ ] ,
138- featureDescriptions : { }
139- } ;
140-
141-
142- const mapStateToProps = ( state , ownProps ) => {
143- const featuresList = state . features . featsWithCheckedTags ;
144-
145- const initialValues = { } ;
146- featuresList . map ( ( f , idx ) => { initialValues [ f ] = true ; return null ; } ) ;
147-
148- const filteredDatasets = state . datasets . filter ( dataset =>
149- ( dataset . project_id === ownProps . selectedProject . id ) ) ;
150- const zerothDataset = filteredDatasets [ 0 ] ;
151-
152- return {
153- featuresByCategory : state . features . features_by_category ,
154- tagList : state . features . tagList ,
155- featuresList,
156- featureDescriptions : state . features . descriptions ,
157- datasets : filteredDatasets ,
158- fields : featuresList . concat (
159- [ 'datasetID' , 'featuresetName' , 'customFeatsCode' ]
160- ) ,
161- initialValues : { ...initialValues ,
162- datasetID : zerothDataset ? zerothDataset . id . toString ( ) : "" ,
163- customFeatsCode : "" }
164- } ;
165- } ;
166-
167- const validate = Validate . createValidator ( {
168- datasetID : [ Validate . required ] ,
169- featuresetName : [ Validate . required ]
170- } ) ;
171-
172- FeaturizeForm = reduxForm ( {
173- form : 'featurize' ,
174- fields : [ '' ] ,
175- validate
176- } , mapStateToProps ) ( FeaturizeForm ) ;
15+ import UploadFeaturesForm from './UploadFeaturesForm' ;
16+ import FeaturizeForm from './FeaturizeForm' ;
17+ import FeaturesetsTable from './FeaturesetsTable' ;
17718
17819
17920let FeaturesTab = ( props ) => {
18021 const { featurePlotURL } = props ;
18122 return (
18223 < div >
18324 < div >
184- < Expand label = "Compute New Features" id = "featsetFormExpander" >
25+ < Expand label = " Compute New Features" id = "featsetFormExpander" >
18526 < FeaturizeForm
18627 onSubmit = { props . computeFeatures }
18728 selectedProject = { props . selectedProject }
18829 />
18930 </ Expand >
19031 </ div >
19132
192- < FeatureTable
33+ < div >
34+ < Expand label = " Upload Pre-Computed Features" id = "uploadFeatsFormExpander" >
35+ < UploadFeaturesForm
36+ onSubmit = { props . uploadFeatures }
37+ selectedProject = { props . selectedProject }
38+ />
39+ </ Expand >
40+ </ div >
41+
42+ < FeaturesetsTable
19343 selectedProject = { props . selectedProject }
19444 featurePlotURL = { featurePlotURL }
19545 />
@@ -214,90 +64,4 @@ const ftMapDispatchToProps = dispatch => (
21464
21565FeaturesTab = connect ( null , ftMapDispatchToProps ) ( FeaturesTab ) ;
21666
217- export let FeatureTable = props => (
218- < div >
219- < table className = "table" >
220- < thead >
221- < tr >
222- < th style = { { width : '15em' } } > Name</ th >
223- < th style = { { width : '15em' } } > Created</ th >
224- < th style = { { width : '15em' } } > Status</ th >
225- < th style = { { width : '15em' } } > Actions</ th >
226- < th style = { { width : 'auto' } } /> { /* extra column for spacing */ }
227- </ tr >
228- </ thead >
229-
230- {
231- props . featuresets . map ( ( featureset , idx ) => {
232- const done = featureset . finished ;
233- const foldedContent = done && (
234- < tr key = { `plot${ featureset . id } ` } >
235- < td colSpan = { 4 } >
236- < Plot url = { `${ props . featurePlotURL } /${ featureset . id } ` } />
237- </ td >
238- </ tr > ) ;
239-
240- let elapsed = "" ;
241- let percent = "" ;
242- if ( featureset . progress ) {
243- ( { elapsed, percent } = { ...featureset . progress } ) ;
244- }
245-
246- let status ;
247- if ( done ) {
248- status = < td > Completed { reformatDatetime ( featureset . finished ) } </ td > ;
249- } else if ( elapsed == "" ) {
250- status = < td > In progress...</ td > ;
251- } else {
252- status = < td > In progress: { percent } %, { elapsed } s</ td > ;
253- }
254-
255- return (
256- < FoldableRow key = { idx } >
257- < tr key = { featureset . id } >
258- < td > { featureset . name } </ td >
259- < td > { reformatDatetime ( featureset . created_at ) } </ td >
260- { status }
261- < td >
262- {
263- done &&
264- < Download url = { `/features/${ featureset . id } /download` } />
265- }
266-
267- < DeleteFeatureset ID = { featureset . id } />
268- </ td >
269- </ tr >
270- { foldedContent }
271- </ FoldableRow >
272- ) ;
273- } )
274- }
275-
276- </ table >
277- </ div >
278- ) ;
279- FeatureTable . propTypes = {
280- featuresets : PropTypes . arrayOf ( PropTypes . object ) . isRequired ,
281- featurePlotURL : PropTypes . string
282- } ;
283- FeatureTable . defaultProps = {
284- featurePlotURL : null
285- } ;
286-
287-
288- const ftMapStateToProps = ( state , ownProps ) => (
289- {
290- featuresets : state . featuresets . filter (
291- fs => ( fs . project_id === ownProps . selectedProject . id )
292- )
293- }
294- ) ;
295-
296- FeatureTable = connect ( ftMapStateToProps ) ( FeatureTable ) ;
297-
298- const mapDispatchToProps = dispatch => (
299- { delete : id => dispatch ( Action . deleteFeatureset ( id ) ) }
300- ) ;
301- const DeleteFeatureset = connect ( null , mapDispatchToProps ) ( Delete ) ;
302-
30367export default FeaturesTab ;
0 commit comments