Skip to content
Snippets Groups Projects
Commit 7126c999 authored by Lewis Liu's avatar Lewis Liu
Browse files

Integrated redux form with custom select component

parent 625928dc
Branches
Tags
No related merge requests found
......@@ -5,6 +5,8 @@ import { Link } from "react-router";
import * as MetabaseCore from "metabase/lib/core";
import { isNumeric } from "metabase/lib/schema_metadata";
import i from 'icepick';
import S from "metabase/components/List.css";
import F from "./Field.css";
......@@ -32,36 +34,41 @@ const Field = ({
className={S.itemTitleTextInput}
type="text"
placeholder={field.display_name}
defaultValue={field.display_name}
{...formField.display_name}
/> :
<Link to={url} className={S.itemName}>{field.display_name}</Link>
}
</div>
<div className={F.fieldType}>
<Select
placeholder="Select a field type"
value={MetabaseCore.field_special_types_map[field.special_type]}
options={
MetabaseCore.field_special_types
.concat({
'id': null,
'name': 'No special type',
'section': 'Other'
})
.filter(type => !isNumeric(field) ?
!(type.id && type.id.startsWith("timestamp_")) :
true
)
}
/>
{ isEditing ?
<Select
placeholder="Select a field type"
value={MetabaseCore.field_special_types_map[field.special_type]}
options={
MetabaseCore.field_special_types
.concat({
'id': null,
'name': 'No field type',
'section': 'Other'
})
.filter(type => !isNumeric(field) ?
!(type.id && type.id.startsWith("timestamp_")) :
true
)
}
onChange={(type) => formField.special_type.onChange(type.id)}
/> :
<span>
{ i.getIn(
MetabaseCore.field_special_types_map,
[field.special_type, 'name']
) || 'No field type'
}
</span>
}
</div>
<div className={F.fieldDataType}>
<input
className={S.itemTitleTextInput}
type="text"
placeholder={field.display_name}
defaultValue={field.display_name}
/>
{field.base_type}
</div>
</div>
<div className={cx(S.itemSubtitle, { "mt1" : true })}>
......
......@@ -93,7 +93,6 @@ export default class EntityItem extends Component {
await this.props[section.update](newEntity);
endEditing();
})}
hasRevisionHistory={hasRevisionHistory}
>
{ isEditing &&
<div className={R.subheader}>
......
......@@ -2,6 +2,8 @@
import React, { Component, PropTypes } from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { reduxForm } from "redux-form";
import i from "icepick";
import S from "metabase/components/List.css";
import R from "metabase/reference/Reference.css";
......@@ -26,24 +28,42 @@ import {
import * as metadataActions from "metabase/redux/metadata";
import * as actions from 'metabase/reference/reference';
const mapStateToProps = (state, props) => ({
section: getSection(state),
fields: getData(state),
loading: getLoading(state),
error: getError(state),
user: getUser(state),
isEditing: getIsEditing(state)
});
const fieldsToFormFields = (fields) => Object.keys(fields);
const mapStateToProps = (state, props) => {
const data = getData(state);
return {
section: getSection(state),
entities: data,
loading: getLoading(state),
error: getError(state),
user: getUser(state),
isEditing: getIsEditing(state),
fields: Object.keys(data)
.map(key => [`${key}.display_name`, `${key}.special_type`])
.reduce((array, keys) => array.concat(keys), [])
};
}
const mapDispatchToProps = {
...metadataActions,
...actions
};
const validate = (values, props) => {
console.log(values);
return {};
}
@connect(mapStateToProps, mapDispatchToProps)
@reduxForm({
form: 'fields',
validate
})
export default class ReferenceEntityList extends Component {
static propTypes = {
style: PropTypes.object.isRequired,
entities: PropTypes.object.isRequired,
fields: PropTypes.object.isRequired,
section: PropTypes.object.isRequired,
loading: PropTypes.bool,
......@@ -52,6 +72,7 @@ export default class ReferenceEntityList extends Component {
render() {
const {
entities,
fields,
style,
section,
......@@ -61,6 +82,7 @@ export default class ReferenceEntityList extends Component {
isEditing,
startEditing,
endEditing,
handleSubmit,
submitting
} = this.props;
......@@ -68,82 +90,92 @@ export default class ReferenceEntityList extends Component {
icon: 'mine',
message: 'You haven\'t added any databases yet.'
};
console.log(fields);
return (
<div className="full">
{ isEditing &&
<div className={R.subheader}>
<div>
You are editing this page
</div>
<div className={R.subheaderButtons}>
<button
className={cx("Button", "Button--white", "Button--small", R.saveButton)}
type="submit"
disabled={submitting}
>
SAVE
</button>
<button
type="button"
className={cx("Button", "Button--white", "Button--small", R.cancelButton)}
onClick={endEditing}
>
CANCEL
</button>
</div>
</div>
}
<div className="wrapper wrapper--trim">
<div className={S.header}>
<div className={S.leftIcons}>
{ section.headerIcon &&
<Icon
className="text-brand"
name={section.headerIcon}
width={24}
height={24}
/>
}
</div>
{section.name}
{ user.is_superuser && !isEditing &&
<div className={S.headerButton}>
<a
onClick={startEditing}
className={cx("Button", "Button--borderless", R.editButton)}
<form
onSubmit={handleSubmit(async fields => {
console.log(fields)
endEditing();
})}
>
{ isEditing &&
<div className={R.subheader}>
<div>
You are editing this page
</div>
<div className={R.subheaderButtons}>
<button
className={cx("Button", "Button--white", "Button--small", R.saveButton)}
type="submit"
disabled={submitting}
>
SAVE
</button>
<button
type="button"
className={cx("Button", "Button--white", "Button--small", R.cancelButton)}
onClick={endEditing}
>
<div className="flex align-center relative">
<Icon name="pencil" width="16px" height="16px" />
<span className="ml1">Edit</span>
</div>
</a>
CANCEL
</button>
</div>
}
</div>
</div>
<LoadingAndErrorWrapper loading={!error && loading} error={error}>
{ () => Object.keys(fields).length > 0 ?
</div>
}
<div className="wrapper wrapper--trim">
<List>
{ Object.values(fields).map(field =>
field && field.id && field.name &&
<li className="relative" key={field.id}>
<Field
field={field}
url={`${section.id}/${field.id}`}
icon="star"
isEditing={isEditing}
/>
</li>
)}
</List>
</div>
:
<div className={S.empty}>
<EmptyState message={empty.message} icon={empty.icon} />
<div className={S.header}>
<div className={S.leftIcons}>
{ section.headerIcon &&
<Icon
className="text-brand"
name={section.headerIcon}
width={24}
height={24}
/>
}
</div>
{section.name}
{ user.is_superuser && !isEditing &&
<div className={S.headerButton}>
<a
onClick={startEditing}
className={cx("Button", "Button--borderless", R.editButton)}
>
<div className="flex align-center relative">
<Icon name="pencil" width="16px" height="16px" />
<span className="ml1">Edit</span>
</div>
</a>
</div>
}
</div>
</div>
}
</LoadingAndErrorWrapper>
<LoadingAndErrorWrapper loading={!error && loading} error={error}>
{ () => Object.keys(entities).length > 0 ?
<div className="wrapper wrapper--trim">
<List>
{ Object.values(entities).map(entity =>
entity && entity.id && entity.name &&
<li className="relative" key={entity.id}>
<Field
field={entity}
url={`${section.id}/${entity.id}`}
icon="star"
isEditing={isEditing}
formField={fields[entity.id]}
/>
</li>
)}
</List>
</div>
:
<div className={S.empty}>
<EmptyState message={empty.message} icon={empty.icon} />
</div>
}
</LoadingAndErrorWrapper>
</form>
</div>
)
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment