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

Alert page - migrate to React and redesign #4153

Merged
merged 14 commits into from
Oct 7, 2019
Binary file modified client/app/assets/images/destinations/hangouts_chat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions client/app/assets/less/ant.less
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@
font-weight: normal;
}

.ant-select-dropdown-menu-item em {
color: @input-color-placeholder;
font-size: 11px;
}

// Fix for disabled button styles inside Tooltip component.
// Tooltip wraps disabled buttons with `<span>` and moves all styles
// and classes to that `<span>`. This resets all button styles and
Expand Down Expand Up @@ -362,4 +367,10 @@
border-radius: 50%;
}
}

// for form items that contain text
&.form-item-line-height-normal .@{form-prefix-cls}-item-control {
line-height: 20px;
margin-top: 9px;
}
}
69 changes: 39 additions & 30 deletions client/app/assets/less/inc/alert.less
Original file line number Diff line number Diff line change
@@ -1,44 +1,53 @@
.alert {
padding: 15px;
.alert-page h3 {
flex-grow: 1;

span {
cursor: pointer;
input {
margin: -0.2em 0;
width: 100%;
min-width: 170px;
}
}

.alert-dismissable,
.alert-dismissible {
padding-right: 44px;
}

.alert-inverse {
.alert-variant(@alert-inverse-bg; @alert-inverse-border; @alert-inverse-text);
.btn-create-alert[disabled] {
display: block;
margin-top: -20px;
}

.alert-link {
color: #fff !important;
font-weight: normal !important;
text-decoration: underline;
}
.alert-state {
border-bottom: 1px solid @input-border;
padding-bottom: 30px;

.growl-animated {
&.alert-inverse {
box-shadow: 0 0 5px fade(@alert-inverse-bg, 50%);
}

&.alert-info {
box-shadow: 0 0 5px fade(@alert-info-bg, 50%);
.alert-state-indicator {
text-transform: uppercase;
font-size: 14px;
padding: 5px 8px;
}

&.alert-success {
box-shadow: 0 0 5px fade(@alert-success-bg, 50%);
.alert-last-triggered {
color: @headings-color;
}
}

&.alert-warning {
box-shadow: 0 0 5px fade(@alert-warning-bg, 50%);
}
.alert-query-selector {
min-width: 250px;
width: auto !important;
}

&.alert-danger {
box-shadow: 0 0 5px fade(@alert-danger-bg, 50%);
// allow form item labels to gracefully break line
.alert-form-item label {
white-space: initial;
padding-right: 8px;
line-height: 21px;

&::after {
margin-right: 0 !important;
}
}

.alert-actions {
flex-grow: 1;
display: flex;
justify-content: flex-end;
align-items: center;
margin-right: -15px;
}
1 change: 1 addition & 0 deletions client/app/assets/less/inc/ant-variables.less
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
-----------------------------------------------------------*/
@input-height-base: 35px;
@input-color: #595959;
@input-color-placeholder: #b4b4b4;
@border-radius-base: 2px;
@border-color-base: #E8E8E8;

Expand Down
4 changes: 4 additions & 0 deletions client/app/assets/less/inc/base.less
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ text.slicetext {
}
}

.warning-icon-danger {
color: @red !important;
}

// page
.page-header--new .btn-favourite, .page-header--new .btn-archive {
font-size: 19px;
Expand Down
2 changes: 2 additions & 0 deletions client/app/assets/less/inc/generics.less
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@

.font-size(20, 8px, 8);

.f-inherit { font-size: inherit !important; }


/* --------------------------------------------------------
Font Weight
Expand Down
53 changes: 40 additions & 13 deletions client/app/components/EmailSettingsWarning.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,49 @@
import React from 'react';
import PropTypes from 'prop-types';
import { react2angular } from 'react2angular';
import { currentUser, clientConfig } from '@/services/auth';
import cx from 'classnames';
import { clientConfig, currentUser } from '@/services/auth';
import Tooltip from 'antd/lib/tooltip';
import Alert from 'antd/lib/alert';
import { HelpTrigger } from '@/components/HelpTrigger';

export function EmailSettingsWarning({ featureName }) {
return (clientConfig.mailSettingsMissing && currentUser.isAdmin) ? (
<p className="alert alert-danger">
{`It looks like your mail server isn't configured. Make sure to configure it for the ${featureName} to work.`}
</p>
) : null;
export default function EmailSettingsWarning({ featureName, className, mode, adminOnly }) {
if (!clientConfig.mailSettingsMissing) {
return null;
}

if (adminOnly && !currentUser.isAdmin) {
return null;
}

const message = (
<span>
Your mail server isn&apos;t configured correctly, and is needed for {featureName} to work.{' '}
<HelpTrigger type="MAIL_CONFIG" className="f-inherit" />
</span>
);

if (mode === 'icon') {
return (
<Tooltip title={message}>
<i className={cx('fa fa-exclamation-triangle', className)} />
</Tooltip>
);
}

return (
<Alert message={message} type="error" className={className} />
);
}

EmailSettingsWarning.propTypes = {
featureName: PropTypes.string.isRequired,
className: PropTypes.string,
mode: PropTypes.oneOf(['alert', 'icon']),
adminOnly: PropTypes.bool,
};

export default function init(ngModule) {
ngModule.component('emailSettingsWarning', react2angular(EmailSettingsWarning));
}

init.init = true;
EmailSettingsWarning.defaultProps = {
className: null,
mode: 'alert',
adminOnly: false,
};
12 changes: 12 additions & 0 deletions client/app/components/HelpTrigger.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ export const TYPES = {
'/user-guide/querying/query-results-data-source',
'Guide: Help Setting up Query Results',
],
ALERT_SETUP: [
'/user-guide/alerts/setting-up-an-alert',
'Guide: Setting Up a New Alert',
],
MAIL_CONFIG: [
'/open-source/setup/#Mail-Configuration',
'Guide: Mail Configuration',
],
ALERT_NOTIF_TEMPLATE_GUIDE: [
'/user-guide/alerts/custom-alert-notifications',
'Guide: Custom Alerts Notifications',
],
};

export class HelpTrigger extends React.Component {
Expand Down
10 changes: 7 additions & 3 deletions client/app/components/QuerySelector.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,11 +146,13 @@ export function QuerySelector(props) {
notFoundContent={null}
filterOption={false}
defaultActiveFirstOption={false}
className={props.className}
data-test="QuerySelector"
>
{searchResults && searchResults.map((q) => {
const disabled = q.is_draft;
return (
<Option value={q.id} key={q.id} disabled={disabled}>
<Option value={q.id} key={q.id} disabled={disabled} className="query-selector-result" data-test={`QueryId${q.id}`}>
{q.name}{' '}
<QueryTagsControl isDraft={q.is_draft} tags={q.tags} className={cx('inline-tags-control', { disabled })} />
</Option>
Expand All @@ -161,7 +163,7 @@ export function QuerySelector(props) {
}

return (
<React.Fragment>
<span data-test="QuerySelector">
{selectedQuery ? (
<Input value={selectedQuery.name} suffix={clearIcon} readOnly />
) : (
Expand All @@ -175,20 +177,22 @@ export function QuerySelector(props) {
<div className="scrollbox" style={{ maxHeight: '50vh', marginTop: 15 }}>
{searchResults && renderResults()}
</div>
</React.Fragment>
</span>
);
}

QuerySelector.propTypes = {
onChange: PropTypes.func.isRequired,
selectedQuery: PropTypes.object, // eslint-disable-line react/forbid-prop-types
type: PropTypes.oneOf(['select', 'default']),
className: PropTypes.string,
disabled: PropTypes.bool,
};

QuerySelector.defaultProps = {
selectedQuery: null,
type: 'default',
className: null,
disabled: false,
};

Expand Down
67 changes: 42 additions & 25 deletions client/app/components/SelectItemsDialog.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { filter, debounce, find } from 'lodash';
import { filter, debounce, find, isEmpty, size } from 'lodash';
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Modal from 'antd/lib/modal';
import Input from 'antd/lib/input';
import List from 'antd/lib/list';
import Button from 'antd/lib/button';
import { wrap as wrapDialog, DialogPropType } from '@/components/DialogWrapper';
import { BigMessage } from '@/components/BigMessage';

Expand All @@ -29,6 +30,9 @@ class SelectItemsDialog extends React.Component {
// right list; args/results save as for `renderItem`. if not specified - `renderItem` will be used
renderStagedItem: PropTypes.func,
save: PropTypes.func, // (selectedItems[]) => Promise<any>
width: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
extraFooterContent: PropTypes.node,
showCount: PropTypes.bool,
};

static defaultProps = {
Expand All @@ -37,8 +41,11 @@ class SelectItemsDialog extends React.Component {
selectedItemsTitle: 'Selected items',
itemKey: item => item.id,
renderItem: () => '',
renderStagedItem: null, // use `renderItem` by default
renderStagedItem: null, // hidden by default
save: items => items,
width: '80%',
extraFooterContent: null,
showCount: false,
};

state = {
Expand Down Expand Up @@ -108,7 +115,7 @@ class SelectItemsDialog extends React.Component {
renderItem(item, isStagedList) {
const { renderItem, renderStagedItem } = this.props;
const isSelected = this.isSelected(item);
const render = isStagedList ? (renderStagedItem || renderItem) : renderItem;
const render = isStagedList ? renderStagedItem : renderItem;

const { content, className, isDisabled } = render(item, { isSelected });

Expand All @@ -123,37 +130,45 @@ class SelectItemsDialog extends React.Component {
}

render() {
const { dialog, dialogTitle, inputPlaceholder, selectedItemsTitle } = this.props;
const { dialog, dialogTitle, inputPlaceholder } = this.props;
const { selectedItemsTitle, renderStagedItem, width, showCount } = this.props;
const { loading, saveInProgress, items, selected } = this.state;
const hasResults = items.length > 0;
return (
<Modal
{...dialog.props}
width="80%"
className="select-items-dialog"
width={width}
title={dialogTitle}
okText="Save"
okButtonProps={{
loading: saveInProgress,
disabled: selected.length === 0,
}}
onOk={() => this.save()}
footer={(
<div className="d-flex align-items-center">
<span className="flex-fill m-r-5" style={{ textAlign: 'left', color: 'rgba(0, 0, 0, 0.5)' }}>{this.props.extraFooterContent}</span>
<Button onClick={dialog.dismiss}>Cancel</Button>
<Button onClick={() => this.save()} loading={saveInProgress} disabled={selected.length === 0} type="primary">
Save
{showCount && !isEmpty(selected) ? ` (${size(selected)})` : null}
</Button>
</div>
)}
>
<div className="d-flex align-items-center m-b-10">
<div className="w-50 m-r-10">
<div className="flex-fill">
<Input.Search
defaultValue={this.state.searchTerm}
onChange={event => this.search(event.target.value)}
placeholder={inputPlaceholder}
autoFocus
/>
</div>
<div className="w-50 m-l-10">
<h5 className="m-0">{selectedItemsTitle}</h5>
</div>
{renderStagedItem && (
<div className="w-50 m-l-20">
<h5 className="m-0">{selectedItemsTitle}</h5>
</div>
)}
</div>

<div className="d-flex align-items-stretch" style={{ minHeight: '30vh', maxHeight: '50vh' }}>
<div className="w-50 m-r-10 scrollbox">
<div className="flex-fill scrollbox">
{loading && <LoadingState className="" />}
{!loading && !hasResults && (
<BigMessage icon="fa-search" message="No items match your search." className="" />
Expand All @@ -166,15 +181,17 @@ class SelectItemsDialog extends React.Component {
/>
)}
</div>
<div className="w-50 m-l-10 scrollbox">
{(selected.length > 0) && (
<List
size="small"
dataSource={selected}
renderItem={item => this.renderItem(item, true)}
/>
)}
</div>
{renderStagedItem && (
<div className="w-50 m-l-20 scrollbox">
{(selected.length > 0) && (
<List
size="small"
dataSource={selected}
renderItem={item => this.renderItem(item, true)}
/>
)}
</div>
)}
</div>
</Modal>
);
Expand Down
Loading