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 55 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
104 changes: 0 additions & 104 deletions client/app/assets/less/redash/redash-newstyle.less
Original file line number Diff line number Diff line change
Expand Up @@ -242,110 +242,6 @@ body {
float: right;
}

.database-source {
display: inline-flex;
flex-wrap: wrap;
justify-content: center;
}

.visual-card {
background: #FFFFFF;
border: 1px solid fade(@redash-gray, 15%);
border-radius: 3px;
margin: 5px;
width: 212px;
padding: 15px 5px;
cursor: pointer;
box-shadow: none;
transition: transform 0.12s ease-out;
transition-duration: 0.3s;
transition-property: box-shadow;

display: flex;
//flex-direction: row;
align-items: center;

&:hover {
box-shadow: rgba(102, 136, 153, 0.15) 0px 4px 9px -3px;
}

img {
width: 64px !important;
height: 64px !important;
margin-right: 5px;
}

h3 {
font-size: 13px;
color: #323232;
margin: 0 !important;
text-overflow: ellipsis;
overflow: hidden;
}
}

.visual-card--selected {
background: fade(@redash-gray, 3%);
border: 1px solid fade(@redash-gray, 15%);
border-radius: 3px;
padding: 0 15px;
box-shadow: none;

display: flex;
flex-direction: row;
align-items: center;

justify-content: space-around;
margin-bottom: 15px;
width: 100%;

img {
width: 64px;
height: 64px;
}

a {
cursor: pointer;
}
}

@media (max-width: 1200px) {
.visual-card {
width: 217px;
}
}

@media (max-width: 755px) {
.visual-card {
width: 47%;
}
}

@media (max-width: 515px) {
.visual-card {
width: 47%;

img {
width: 48px;
height: 48px;
}
}
}

@media (max-width: 408px) {
.visual-card {
width: 100%;
padding: 5px;
margin: 5px 0;

img {
width: 48px;
height: 48px;
}
}
}


.t-header:not(.th-alt) {
padding: 15px;

Expand Down
191 changes: 191 additions & 0 deletions client/app/components/CreateSourceDialog.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
import React from 'react';
import PropTypes from 'prop-types';
import { isEmpty, toUpper, includes } from 'lodash';
import Button from 'antd/lib/button';
import List from 'antd/lib/list';
import Modal from 'antd/lib/modal';
import Input from 'antd/lib/input';
import Steps from 'antd/lib/steps';
import { wrap as wrapDialog, DialogPropType } from '@/components/DialogWrapper';
import { PreviewCard } from '@/components/PreviewCard';
import EmptyState from '@/components/items-list/components/EmptyState';
import DynamicForm from '@/components/dynamic-form/DynamicForm';
import helper from '@/components/dynamic-form/dynamicFormHelper';
import { HelpTrigger, TYPES as HELP_TRIGGER_TYPES } from '@/components/HelpTrigger';

const { Step } = Steps;
const { Search } = Input;

const StepEnum = {
SELECT_TYPE: 0,
CONFIGURE_IT: 1,
DONE: 2,
};

class CreateSourceDialog extends React.Component {
static propTypes = {
dialog: DialogPropType.isRequired,
types: PropTypes.arrayOf(PropTypes.object),
sourceType: PropTypes.string.isRequired,
imageFolder: PropTypes.string.isRequired,
helpTriggerPrefix: PropTypes.string,
onCreate: PropTypes.func.isRequired,
};

static defaultProps = {
types: [],
helpTriggerPrefix: null,
};

state = {
searchText: '',
selectedType: null,
savingSource: false,
currentStep: StepEnum.SELECT_TYPE,
};

selectType = (selectedType) => {
this.setState({ selectedType, currentStep: StepEnum.CONFIGURE_IT });
};

resetType = () => {
if (this.state.currentStep === StepEnum.CONFIGURE_IT) {
this.setState({ searchText: '', selectedType: null, currentStep: StepEnum.SELECT_TYPE });
}
};

createSource = (values, successCallback, errorCallback) => {
const { selectedType, savingSource } = this.state;
if (!savingSource) {
this.setState({ savingSource: true, currentStep: StepEnum.DONE });
this.props.onCreate(selectedType, values).then(() => {
successCallback('Saved.');
this.props.dialog.close({ success: true });
}).catch((error) => {
this.setState({ savingSource: false, currentStep: StepEnum.CONFIGURE_IT });
errorCallback(error.message);
});
}
};

renderTypeSelector() {
const { types } = this.props;
const { searchText } = this.state;
const filteredTypes = types.filter(type => isEmpty(searchText) ||
includes(type.name.toLowerCase(), searchText.toLowerCase()));
return (
<div className="m-t-10">
<Search
placeholder="Search..."
onChange={e => this.setState({ searchText: e.target.value })}
autoFocus
data-test="SearchSource"
/>
<div className="scrollbox p-5 m-t-10" style={{ minHeight: '30vh', maxHeight: '40vh' }}>
{isEmpty(filteredTypes) ? (<EmptyState className="" />) : (
<List
size="small"
dataSource={filteredTypes}
renderItem={item => this.renderItem(item)}
/>
)}
</div>
</div>
);
}

renderForm() {
const { imageFolder, helpTriggerPrefix } = this.props;
const { selectedType } = this.state;
const fields = helper.getFields(selectedType);
const helpTriggerType = `${helpTriggerPrefix}${toUpper(selectedType.type)}`;
return (
<div className="p-5">
<div className="d-flex justify-content-center align-items-center">
<img
className="p-5"
src={`${imageFolder}/${selectedType.type}.png`}
alt={selectedType.name}
width="48"
/>
ranbena marked this conversation as resolved.
Show resolved Hide resolved
<h4 className="m-0">{selectedType.name}</h4>
</div>
<div className="text-right">
{HELP_TRIGGER_TYPES[helpTriggerType] && (
<HelpTrigger className="f-13" type={helpTriggerType}>
Setup Instructions <i className="fa fa-question-circle" />
</HelpTrigger>
)}
</div>
<DynamicForm
id="sourceForm"
fields={fields}
onSubmit={this.createSource}
feedbackIcons
hideSubmitButton
/>
</div>
);
}

renderItem(item) {
const { imageFolder } = this.props;
return (
<List.Item
className="p-l-10 p-r-10 clickable"
onClick={() => this.selectType(item)}
>
<PreviewCard title={item.name} imageUrl={`${imageFolder}/${item.type}.png`} roundedImage={false}>
<i className="fa fa-angle-double-right" />
</PreviewCard>
</List.Item>
);
}

render() {
const { currentStep, savingSource } = this.state;
const { dialog, sourceType } = this.props;
return (
<Modal
{...dialog.props}
title={`Create a New ${sourceType}`}
footer={(currentStep === StepEnum.SELECT_TYPE) ? [
(<Button key="cancel" onClick={() => dialog.dismiss()}>Cancel</Button>),
(<Button key="submit" type="primary" disabled>Create</Button>),
] : [
(<Button key="previous" onClick={this.resetType}>Previous</Button>),
(
<Button
key="submit"
htmlType="submit"
form="sourceForm"
type="primary"
loading={savingSource}
data-test="CreateSourceButton"
>
Create
</Button>
),
]}
>
<div data-test="CreateSourceDialog">
<Steps className="hidden-xs m-b-10" size="small" current={currentStep} progressDot>
{currentStep === StepEnum.CONFIGURE_IT ? (
<Step
title={<a>Type Selection</a>}
className="clickable"
onClick={this.resetType}
/>
) : (<Step title="Type Selection" />)}
<Step title="Configuration" />
<Step title="Done" />
</Steps>
{currentStep === StepEnum.SELECT_TYPE && this.renderTypeSelector()}
{currentStep !== StepEnum.SELECT_TYPE && this.renderForm()}
</div>
</Modal>
);
}
}

export default wrapDialog(CreateSourceDialog);
39 changes: 37 additions & 2 deletions client/app/components/HelpTrigger.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import './HelpTrigger.less';
const DOMAIN = 'https://redash.io';
const HELP_PATH = '/help';
const IFRAME_TIMEOUT = 20000;
const TYPES = {

export const TYPES = {
HOME: [
'',
'Help',
Expand All @@ -25,16 +26,50 @@ const TYPES = {
'/user-guide/dashboards/sharing-dashboards',
'Guide: Sharing and Embedding Dashboards',
],
DS_ATHENA: [
'/data-sources/amazon-athena-setup',
'Guide: Help Setting up Amazon Athena',
],
DS_BIGQUERY: [
'/data-sources/bigquery-setup',
'Guide: Help Setting up BigQuery',
],
DS_URL: [
'/data-sources/querying-urls',
'Guide: Help Setting up URL',
],
DS_MONGODB: [
'/data-sources/mongodb-setup',
'Guide: Help Setting up MongoDB',
],
DS_GOOGLE_SPREADSHEETS: [
'/data-sources/querying-a-google-spreadsheet',
'Guide: Help Setting up Google Spreadsheets',
],
DS_GOOGLE_ANALYTICS: [
'/data-sources/google-analytics-setup',
'Guide: Help Setting up Google Analytics',
],
DS_AXIBASETSD: [
'/data-sources/axibase-time-series-database',
'Guide: Help Setting up Axibase Time Series',
],
DS_RESULTS: [
'/user-guide/querying/query-results-data-source',
'Guide: Help Setting up Query Results',
],
};

export class HelpTrigger extends React.Component {
static propTypes = {
type: PropTypes.oneOf(Object.keys(TYPES)).isRequired,
className: PropTypes.string,
children: PropTypes.node,
}

static defaultProps = {
className: null,
children: <i className="fa fa-question-circle" />,
};

iframeRef = null
Expand Down Expand Up @@ -92,7 +127,7 @@ export class HelpTrigger extends React.Component {
<React.Fragment>
<Tooltip title={tooltip}>
<a href="javascript: void(0)" onClick={this.openDrawer} className={className}>
<i className="fa fa-question-circle" />
{this.props.children}
</a>
</Tooltip>
<Drawer
Expand Down
Loading