Skip to content

Commit f676bd4

Browse files
committed
Reorganize Features tab components into separate files
1 parent bfca4eb commit f676bd4

File tree

4 files changed

+253
-251
lines changed

4 files changed

+253
-251
lines changed

static/js/components/Features.jsx

Lines changed: 15 additions & 251 deletions
Original file line numberDiff line numberDiff line change
@@ -5,191 +5,41 @@ import { reduxForm } from 'redux-form';
55
import ReactTabs from 'react-tabs';
66

77
import { FormComponent, Form, TextInput, TextareaInput, SubmitButton,
8-
CheckBoxInput, SelectInput } from './Form';
8+
CheckBoxInput, SelectInput } from './Form';
99
import * as Validate from '../validate';
1010
import Expand from './Expand';
1111
import * as Action from '../actions';
1212
import Plot from './Plot';
1313
import FoldableRow from './FoldableRow';
1414
import { 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

17920
let 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

21565
FeaturesTab = 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-
&nbsp;&nbsp;
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-
30367
export default FeaturesTab;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import React from 'react';
2+
import { connect } from 'react-redux';
3+
4+
import { reformatDatetime } from '../utils';
5+
6+
7+
const FeaturesetsTable = props => (
8+
<div>
9+
<h4>Feature Sets</h4>
10+
<table className="table">
11+
<thead>
12+
<tr>
13+
<th style={{ width: '15em' }}>Name</th>
14+
<th style={{ width: '15em' }}>Created</th>
15+
<th style={{ width: '15em' }}>Status</th>
16+
<th style={{ width: '15em' }}>Actions</th>
17+
<th style={{ width: 'auto' }} />{ /* extra column for spacing */ }
18+
</tr>
19+
</thead>
20+
21+
{
22+
props.featuresets.map((featureset, idx) => {
23+
const done = featureset.finished;
24+
const foldedContent = done && (
25+
<tr key={`plot${featureset.id}`}>
26+
<td colSpan={4}>
27+
<Plot url={`${props.featurePlotURL}/${featureset.id}`} />
28+
</td>
29+
</tr>);
30+
31+
const status = done ? <td>Completed {reformatDatetime(featureset.finished)}</td> : <td>In progress</td>;
32+
33+
return (
34+
<FoldableRow key={idx}>
35+
<tr key={featureset.id}>
36+
<td>{featureset.name}</td>
37+
<td>{reformatDatetime(featureset.created_at)}</td>
38+
{status}
39+
<td><DeleteFeatureset ID={featureset.id} /></td>
40+
</tr>
41+
{foldedContent}
42+
</FoldableRow>
43+
); })
44+
}
45+
46+
</table>
47+
</div>
48+
);
49+
FeaturesetsTable.propTypes = {
50+
featuresets: React.PropTypes.arrayOf(React.PropTypes.object),
51+
featurePlotURL: React.PropTypes.string
52+
};
53+
54+
55+
const ftMapStateToProps = (state, ownProps) => (
56+
{
57+
featuresets: state.featuresets.filter(
58+
fs => (fs.project_id === ownProps.selectedProject.id)
59+
)
60+
}
61+
);
62+
63+
export default connect(ftMapStateToProps)(FeaturesetsTable);

0 commit comments

Comments
 (0)