Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Data Sources and Alert Destinations pages to React #3470

Merged
merged 59 commits into from
Mar 28, 2019
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
2d21e2f
Migrate TypePicker to React
gabrieldutra Feb 19, 2019
9aeea93
Migrate DataSources and Destinations List
gabrieldutra Feb 20, 2019
b1e607b
Fixes to DestinationsList
gabrieldutra Feb 20, 2019
f99d54d
Add CreateDataSource (testing with Steps)
gabrieldutra Feb 20, 2019
5c1c31e
Render the form after type selection
gabrieldutra Feb 20, 2019
6b60e74
Add HELP_LINKS to CreateDataSource
gabrieldutra Feb 21, 2019
f51d2c3
Add Done behavior
gabrieldutra Feb 21, 2019
2bfb00b
Add scrollToTop to CreateDataSource
gabrieldutra Feb 21, 2019
5f2d944
TypePicker styling adjusts
gabrieldutra Feb 21, 2019
ced7c92
Add CreateDestination
gabrieldutra Feb 21, 2019
e937b93
Update resouce gets to componentDidMount
gabrieldutra Feb 22, 2019
2758ea8
Create EditForm components
gabrieldutra Feb 22, 2019
d4425d9
Migrate Edit pages
gabrieldutra Feb 22, 2019
39d2630
Remove angular logic from DynamicForm
gabrieldutra Feb 22, 2019
f9fd818
Merge remote-tracking branch 'master' into react-destinations-data-so…
gabrieldutra Feb 22, 2019
5604138
Add actions to EditPages
gabrieldutra Feb 22, 2019
a2501ba
TypePicker title style adjustments
gabrieldutra Feb 23, 2019
b5cf6b9
Add Empty and Loading state
gabrieldutra Feb 24, 2019
2c7de22
UX improvements
gabrieldutra Feb 24, 2019
c09ac8a
Review changes
gabrieldutra Feb 24, 2019
8897569
Styling updates on TypePicker, forms background fix
gabrieldutra Feb 24, 2019
69c483f
Add blank line removed by mistaken
gabrieldutra Feb 24, 2019
9c4e203
Merge remote-tracking branch 'master' into react-destinations-data-so…
gabrieldutra Mar 2, 2019
38ddbc2
Reorganize TypePicker
gabrieldutra Mar 2, 2019
ac19ba6
Merge remote-tracking branch 'master' into react-destinations-data-so…
gabrieldutra Mar 3, 2019
4a96923
Hide Search on List Pages
gabrieldutra Mar 3, 2019
ed5cf82
Fix spacing in Forms
gabrieldutra Mar 3, 2019
ec3f810
Update Create Data Source and Destination to be a Dialog
gabrieldutra Mar 5, 2019
9e621c2
Remove max-height from the form
gabrieldutra Mar 6, 2019
00cbe01
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 6, 2019
554baec
Fix DynamicForm import in CreateUserDialog
gabrieldutra Mar 7, 2019
8a94299
Route /new to open CreateSourceDialog
gabrieldutra Mar 7, 2019
a0cd269
Add HelpTrigger + refine styling and Edit Pages
gabrieldutra Mar 8, 2019
b5cccd9
Remove help links from data source resource
gabrieldutra Mar 8, 2019
55eff65
Update Cypress specs
gabrieldutra Mar 8, 2019
4aa76e0
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 8, 2019
16e471d
TypePicker -> CardsList
gabrieldutra Mar 8, 2019
87366d6
Remove old TypePicker styling and change CardsList styling to less
gabrieldutra Mar 8, 2019
f05af22
Test if Percy shows Dialogs
gabrieldutra Mar 8, 2019
5006db7
Personal review cleanup
gabrieldutra Mar 8, 2019
de79469
CR
gabrieldutra Mar 10, 2019
4f57ca7
Remove unnecessary query on dialog success
gabrieldutra Mar 10, 2019
6c4b434
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 10, 2019
fb65be7
Handle resource errors in Edit Pages
gabrieldutra Mar 10, 2019
ff655b5
Add CreateDestination policy
gabrieldutra Mar 10, 2019
e9c6ed2
Add placeholder and separator to the Name field
gabrieldutra Mar 10, 2019
c5b9799
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 11, 2019
77285d9
Use cy.click instead of cy.wait
gabrieldutra Mar 11, 2019
af9b62a
Revert "Use cy.click instead of cy.wait" (Didn't work)
gabrieldutra Mar 13, 2019
5873fed
Align help trigger on the right and rename Steps
gabrieldutra Mar 13, 2019
a9f4b24
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 14, 2019
10e0d25
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 15, 2019
3130929
Refine behavior for long names
gabrieldutra Mar 15, 2019
ae20478
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 25, 2019
02d647f
Update toastr calls to use notification instead
gabrieldutra Mar 25, 2019
21efba7
Merge branch 'master' into react-destinations-data-sources
gabrieldutra Mar 27, 2019
5810a9e
Redirect to target after creation
gabrieldutra Mar 27, 2019
cbaac32
Remove autoFocus on DynamicForm for Edit Pages
gabrieldutra Mar 27, 2019
0334b92
Add eslint-disable for cy.wait
gabrieldutra Mar 27, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions client/app/assets/less/ant.less
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
@import '~antd/lib/grid/style/index';
@import '~antd/lib/switch/style/index';
@import '~antd/lib/drawer/style/index';
@import '~antd/lib/card/style/index';
@import '~antd/lib/steps/style/index';
@import '~antd/lib/divider/style/index';
@import '~antd/lib/dropdown/style/index';
@import '~antd/lib/menu/style/index';
Expand Down
85 changes: 85 additions & 0 deletions client/app/components/TypePicker.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import Card from 'antd/lib/card';
import Input from 'antd/lib/input';
import List from 'antd/lib/list';
import { includes, isEmpty } from 'lodash';
import PropTypes from 'prop-types';
import React from 'react';
import { Type } from './proptypes';
import EmptyState from '@/components/items-list/components/EmptyState';

const { Search } = Input;
const { Meta } = Card;

export default class TypePicker extends React.Component {
static propTypes = {
types: PropTypes.arrayOf(Type),
};

static defaultProps = {
types: [],
};

constructor(props) {
super(props);
this.state = { searchText: '' };
}

// eslint-disable-next-line class-methods-use-this
renderListItem(item) {
const titleStyle = {
fontSize: '13px',
gabrieldutra marked this conversation as resolved.
Show resolved Hide resolved
maxHeight: '50px',
whiteSpace: 'normal',
textOverflow: 'ellipsis',
};

return (
<List.Item>
<Card
bodyStyle={{ height: '80px', padding: '15px' }}
cover={(
<div className="m-t-10">
<img
alt={item.name}
style={{ margin: 'auto', width: '64px', height: '64px' }}
src={item.imgSrc}
/>
</div>
)}
onClick={item.onClick}
hoverable
>
<Meta title={(<p style={titleStyle}>{item.name}</p>)} />
</Card>
</List.Item>
);
}

render() {
const { types } = this.props;
const { searchText } = this.state;

const filteredTypes = types.filter(type => isEmpty(searchText) ||
includes(type.name.toLowerCase(), searchText.toLowerCase()));

return (
<div className="text-center" data-test="TypePicker">
<Search
className="m-b-20"
placeholder="Search..."
onChange={e => this.setState({ searchText: e.target.value })}
style={{ maxWidth: 300 }}
autoFocus
/>
{isEmpty(filteredTypes) ? (<EmptyState />) : (
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved
<List
className="p-20"
grid={{ gutter: 12, xs: 1, sm: 3, lg: 4, xl: 6 }}
dataSource={filteredTypes}
renderItem={item => this.renderListItem(item)}
/>
)}
</div>
);
}
}
70 changes: 70 additions & 0 deletions client/app/components/data-sources/EditDataSourceForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import PropTypes from 'prop-types';
import { DataSource } from '@/services/data-source';
import DynamicForm from '@/components/dynamic-form/DynamicForm';
import helper from '@/components/dynamic-form/dynamicFormHelper';

const HELP_LINKS = {
athena: 'https://redash.io/help/data-sources/amazon-athena-setup',
bigquery: 'https://redash.io/help/data-sources/bigquery-setup',
url: 'https://redash.io/help/data-sources/querying-urls',
mongodb: 'https://redash.io/help/data-sources/mongodb-setup',
google_spreadsheets: 'https://redash.io/help/data-sources/querying-a-google-spreadsheet',
google_analytics: 'https://redash.io/help/data-sources/google-analytics-setup',
axibasetsd: 'https://redash.io/help/data-sources/axibase-time-series-database',
results: 'https://redash.io/help/user-guide/querying/query-results-data-source',
};

export default function EditDataSourceForm({ dataSource, type, onSuccess, ...props }) {
const selectedType = type.type;
const fields = helper.getFields(type.configuration_schema, dataSource);

const handleSubmit = (values, successCallback, errorCallback) => {
helper.updateTargetWithValues(dataSource, values);
dataSource.$save(
(data) => {
successCallback('Saved.');
onSuccess(data);
},
(error) => {
if (error.status === 400 && 'message' in error.data) {
kravets-levko marked this conversation as resolved.
Show resolved Hide resolved
errorCallback(error.data.message);
} else {
errorCallback('Failed saving.');
}
},
);
};

return (
<div data-test="DataSource">
<div className="col-sm-offset-4 col-sm-4 text-center">
<img src={`${DataSource.IMG_ROOT}/${selectedType}.png`} alt={type.name} width="64" />
<h3>{type.name}</h3>
</div>
<div className="col-sm-4">
{HELP_LINKS[selectedType] && (
<p className="needhelp text-right text-center-xs">
{/* eslint-disable-next-line react/jsx-no-target-blank */}
<a href={HELP_LINKS[selectedType]} target="_blank" rel="noopener">
Help <span className="hidden-xs">setting up {type.name}</span> <i className="fa fa-external-link" aria-hidden="true" />
</a>
</p>
)}
</div>
<div className="col-md-4 col-md-offset-4">
<DynamicForm {...props} fields={fields} onSubmit={handleSubmit} feedbackIcons />
</div>
</div>
);
}

EditDataSourceForm.propTypes = {
dataSource: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
type: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
onSuccess: PropTypes.func,
};

EditDataSourceForm.defaultProps = {
onSuccess: () => {},
};
49 changes: 49 additions & 0 deletions client/app/components/destinations/EditDestinationForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Destination } from '@/services/destination';
import DynamicForm from '@/components/dynamic-form/DynamicForm';
import helper from '@/components/dynamic-form/dynamicFormHelper';

export default function EditDestinationForm({ destination, type, onSuccess, ...props }) {
const selectedType = type.type;
const fields = helper.getFields(type.configuration_schema, destination);

const handleSubmit = (values, successCallback, errorCallback) => {
helper.updateTargetWithValues(destination, values);
destination.$save(
(data) => {
successCallback('Saved.');
onSuccess(data);
},
(error) => {
if (error.status === 400 && 'message' in error.data) {
errorCallback(error.data.message);
} else {
errorCallback('Failed saving.');
}
},
);
};

return (
<div>
<div className="text-center">
<img src={`${Destination.IMG_ROOT}/${selectedType}.png`} alt={type.name} width="64" />
<h3>{type.name}</h3>
</div>
<div className="col-md-4 col-md-offset-4">
<DynamicForm {...props} fields={fields} onSubmit={handleSubmit} feedbackIcons />
</div>
</div>
);
}

EditDestinationForm.propTypes = {
destination: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
type: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
onSuccess: PropTypes.func,
};

EditDestinationForm.defaultProps = {
onSuccess: () => {},
};
35 changes: 2 additions & 33 deletions client/app/components/dynamic-form/DynamicForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import Button from 'antd/lib/button';
import Upload from 'antd/lib/upload';
import Icon from 'antd/lib/icon';
import { includes } from 'lodash';
import { react2angular } from 'react2angular';
import { toastr } from '@/services/ng';
import { Field, Action, AntdForm } from '../proptypes';
import helper from './dynamicFormHelper';
Expand All @@ -23,7 +22,7 @@ const fieldRules = ({ type, required, minLength }) => {
].filter(rule => rule);
};

export const DynamicForm = Form.create()(class DynamicForm extends React.Component {
class DynamicForm extends React.Component {
static propTypes = {
fields: PropTypes.arrayOf(Field),
actions: PropTypes.arrayOf(Action),
Expand Down Expand Up @@ -218,36 +217,6 @@ export const DynamicForm = Form.create()(class DynamicForm extends React.Compone
</Form>
);
}
});

export default function init(ngModule) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

ngModule.component('dynamicForm', react2angular((props) => {
const fields = helper.getFields(props.type.configuration_schema, props.target);

const onSubmit = (values, onSuccess, onError) => {
helper.updateTargetWithValues(props.target, values);
props.target.$save(
() => {
onSuccess('Saved.');
},
(error) => {
if (error.status === 400 && 'message' in error.data) {
onError(error.data.message);
} else {
onError('Failed saving.');
}
},
);
};

const updatedProps = {
fields,
actions: props.target.id ? props.actions : [],
feedbackIcons: true,
onSubmit,
};
return (<DynamicForm {...updatedProps} />);
}, ['target', 'type', 'actions']));
}

init.init = true;
export default Form.create()(DynamicForm);
7 changes: 7 additions & 0 deletions client/app/components/proptypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ export const UserProfile = PropTypes.shape({
isDisabled: PropTypes.bool,
});

export const Type = PropTypes.shape({
type: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
imgSrc: PropTypes.string.isRequired,
onClick: PropTypes.func,
});

function checkMoment(isRequired, props, propName, componentName) {
const value = props[propName];
const isRequiredValid = isRequired && (value !== null);
Expand Down
20 changes: 0 additions & 20 deletions client/app/components/type-picker.html

This file was deleted.

18 changes: 0 additions & 18 deletions client/app/components/type-picker.js

This file was deleted.

2 changes: 1 addition & 1 deletion client/app/components/users/UserEdit.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { User } from '@/services/user';
import { currentUser } from '@/services/auth';
import { absoluteUrl } from '@/services/utils';
import { UserProfile } from '../proptypes';
import { DynamicForm } from '../dynamic-form/DynamicForm';
import DynamicForm from '../dynamic-form/DynamicForm';
import ChangePasswordDialog from './ChangePasswordDialog';
import InputWithCopy from '../InputWithCopy';

Expand Down
Loading