Skip to content

Commit

Permalink
refactor(ui): improve first time alerting experience (#14917)
Browse files Browse the repository at this point in the history
* refactor(ui): move QuestionMarkTooltip into shared folder

* refactor(ui): delete unused component

* refactor(ui): allow QuestionMarkTooltip to wrap other elements

* refactor(ui): Add question mark tooltips to alerting column headers

* refactor(ui): color code buttons to indicate importance and grouping

* refactor(ui): swap order of endpoints and rules columns

* refactor(ui): show "first time" widget when no alerting resources exist

* refactor(ui): update alerting empty copy

* refactor(ui): ensure onboarding tooltips are using the correct prop names

* refactor(ui): remove tests for tooltips in admin step

These should be handled by Clockface instead

* refactor(ui): fix affected e2e test

* chore(ui): update changelog
  • Loading branch information
alexpaxton authored Sep 4, 2019
1 parent ee21140 commit 20f717d
Show file tree
Hide file tree
Showing 21 changed files with 343 additions and 293 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
1. [14694](https://github.com/influxdata/influxdb/pull/14694): Add ability to find tasks by name.

### UI Improvements
1. [14917](https://github.com/influxdata/influxdb/pull/14917): Make first steps in Monitoring & Alerting more obvious
1. [14889](https://github.com/influxdata/influxdb/pull/14889): Make adding data to buckets more discoverable
1. [14709](https://github.com/influxdata/influxdb/pull/14709): Move Buckets, Telgrafs, and Scrapers pages into a tab called "Load Data" for ease of discovery
1. [14846](https://github.com/influxdata/influxdb/pull/14846): Standardize formatting of "updated at" timestamp in all resource cards
Expand Down
2 changes: 1 addition & 1 deletion ui/cypress/e2e/notificationEndpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('Notification Endpoints', () => {
const description =
'A minute, an hour, a month. Notification Endpoint is certain. The time is not.'

cy.getByTestID('alert-column--header create-endpoint').click()
cy.getByTestID('create-endpoint').click()

cy.getByTestID('endpoint-name--input')
.clear()
Expand Down
21 changes: 0 additions & 21 deletions ui/cypress/e2e/onboarding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,27 +75,6 @@ describe('Onboarding', () => {
.children('.cf-button--label')
.contains('Continue')

//Check tooltips
cy.getByTestID('form-elem--orgname')
.children('[data-testid=form--label]')
.children('div.question-mark-tooltip')
.trigger('mouseenter')
.children('div[data-id=tooltip]')
.contains('An organization is')
.should($tt => {
expect($tt).to.have.class('show')
})

cy.getByTestID('form-elem--bucketname')
.children('[data-testid=form--label]')
.children('div.question-mark-tooltip')
.trigger('mouseenter')
.children('div[data-id=tooltip]')
.contains('A bucket is')
.should($tt => {
expect($tt).to.have.class('show')
})

//Input fields
cy.getByTestID('input-field--username').type(user.username)
cy.getByTestID('input-field--password').type(user.password)
Expand Down
30 changes: 30 additions & 0 deletions ui/src/alerting/components/AlertingIndex.scss
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,33 @@
padding: 18px;
padding-top: 0;
}

/*
First time widget
------------------------------------------------------------------------------
*/

.alerting-first-time {
border: $ix-border solid $c-ocean;

h1,
h5 {
user-select: none;
color: $c-neutrino;
}
h1 {
letter-spacing: 0;
margin-top: 0;
}

h5 {
margin-bottom: 0;
line-height: 1.5em;
font-weight: 500;

strong {
font-weight: 900;
color: $g20-white;
}
}
}
8 changes: 4 additions & 4 deletions ui/src/alerting/components/AlertingIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ const AlertingIndex: FunctionComponent = ({children}) => {
</GetResources>
</GridColumn>
<GridColumn widthLG={4} widthMD={4} widthSM={4} widthXS={12}>
<GetResources resource={ResourceTypes.NotificationRules}>
<RulesColumn />
<GetResources resource={ResourceTypes.NotificationEndpoints}>
<EndpointsColumn />
</GetResources>
</GridColumn>
<GridColumn widthLG={4} widthMD={4} widthSM={4} widthXS={12}>
<GetResources resource={ResourceTypes.NotificationEndpoints}>
<EndpointsColumn />
<GetResources resource={ResourceTypes.NotificationRules}>
<RulesColumn />
</GetResources>
</GridColumn>
</GridRow>
Expand Down
86 changes: 44 additions & 42 deletions ui/src/alerting/components/AlertsColumn.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,65 @@
// Libraries
import React, {FC} from 'react'
import React, {FC, ReactChild} from 'react'

// Components
import {
Button,
ComponentColor,
Panel,
InfluxColors,
DapperScrollbars,
Input,
IconFont,
FlexBox,
FlexDirection,
ComponentSize,
} from '@influxdata/clockface'
import QuestionMarkTooltip from 'src/shared/components/question_mark_tooltip/QuestionMarkTooltip'

interface Props {
title: string
testID?: string
onCreate: () => void
createButton: JSX.Element
questionMarkTooltipContents: ReactChild
}

const AlertsColumnHeader: FC<Props> = ({
children,
onCreate,
title,
testID = '',
}) => {
return (
<Panel
backgroundColor={InfluxColors.Kevlar}
className="alerting-index--column"
>
<Panel.Header>
<Panel.Title>{title}</Panel.Title>
<Button
text="Create"
icon={IconFont.Plus}
onClick={onCreate}
color={ComponentColor.Primary}
testID={`alert-column--header ${testID}`}
createButton,
questionMarkTooltipContents,
}) => (
<Panel
backgroundColor={InfluxColors.Kevlar}
className="alerting-index--column"
>
<Panel.Header>
<FlexBox direction={FlexDirection.Row} margin={ComponentSize.Small}>
<Panel.Title style={{fontSize: '17px', width: 'auto'}}>
{title}
</Panel.Title>
<QuestionMarkTooltip
testID={`${title}--question-mark`}
tipContent={questionMarkTooltipContents}
/>
</Panel.Header>
<div className="alerting-index--search">
<Input
icon={IconFont.Search}
placeholder={`Filter ${title}...`}
value=""
onChange={() => {}}
/>
</div>
<div className="alerting-index--column-body">
<DapperScrollbars
autoSize={false}
autoHide={true}
style={{width: '100%', height: '100%'}}
>
<div className="alerting-index--list">{children}</div>
</DapperScrollbars>
</div>
</Panel>
)
}
</FlexBox>
{createButton}
</Panel.Header>
<div className="alerting-index--search">
<Input
icon={IconFont.Search}
placeholder={`Filter ${title}...`}
value=""
onChange={() => {}}
/>
</div>
<div className="alerting-index--column-body">
<DapperScrollbars
autoSize={false}
autoHide={true}
style={{width: '100%', height: '100%'}}
>
<div className="alerting-index--list">{children}</div>
</DapperScrollbars>
</div>
</Panel>
)

export default AlertsColumnHeader
51 changes: 42 additions & 9 deletions ui/src/alerting/components/CheckCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,29 @@ import React, {FunctionComponent} from 'react'

//Components
import CheckCard from 'src/alerting/components/CheckCard'
import {EmptyState, ResourceList} from '@influxdata/clockface'
import {EmptyState, ResourceList, Panel, Gradients} from '@influxdata/clockface'

// Types
import {Check} from 'src/types'
import {ComponentSize} from '@influxdata/clockface'

interface Props {
checks: Check[]
showFirstTimeWidget: boolean
}

const CheckCards: FunctionComponent<Props> = ({checks}) => {
const CheckCards: FunctionComponent<Props> = ({
checks,
showFirstTimeWidget,
}) => {
return (
<>
<ResourceList>
<ResourceList.Body emptyState={<EmptyChecksList />}>
<ResourceList.Body
emptyState={
<EmptyChecksList showFirstTimeWidget={showFirstTimeWidget} />
}
>
{checks.map(check => (
<CheckCard key={check.id} check={check} />
))}
Expand All @@ -27,17 +35,42 @@ const CheckCards: FunctionComponent<Props> = ({checks}) => {
)
}

const EmptyChecksList: FunctionComponent = () => {
interface EmptyProps {
showFirstTimeWidget: boolean
}

const EmptyChecksList: FunctionComponent<EmptyProps> = ({
showFirstTimeWidget,
}) => {
if (showFirstTimeWidget) {
return (
<Panel
gradient={Gradients.GundamPilot}
size={ComponentSize.Large}
className="alerting-first-time"
>
<Panel.Body>
<h1>
Looks like it's your
<br />
first time here
</h1>
<h5>
Welcome to our new Monitoring & Alerting feature!
<br />
Try creating a <strong>Check</strong> to get started
</h5>
</Panel.Body>
</Panel>
)
}

return (
<EmptyState size={ComponentSize.Small} className="alert-column--empty">
<EmptyState.Text
text="A Check is a periodic query that the system performs against your time series data that will generate a status"
text="Looks like you have not created a Check yet LINEBREAK LINEBREAK You will need one to be notified about LINEBREAK any changes in system status"
highlightWords={['Check']}
/>
<br />
<a href="#" target="_blank">
Documentation
</a>
</EmptyState>
)
}
Expand Down
51 changes: 47 additions & 4 deletions ui/src/alerting/components/ChecksColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ import {connect} from 'react-redux'
import {viewableLabels} from 'src/labels/selectors'

// Components
import {Button, IconFont, ComponentColor} from '@influxdata/clockface'
import CheckCards from 'src/alerting/components/CheckCards'
import AlertsColumnHeader from 'src/alerting/components/AlertsColumn'

// Types
import {Check, AppState} from 'src/types'
import {Check, NotificationRuleDraft, AppState} from 'src/types'

interface StateProps {
checks: Check[]
rules: NotificationRuleDraft[]
endpoints: AppState['endpoints']['list']
}

type Props = StateProps & WithRouterProps
Expand All @@ -23,13 +26,46 @@ const ChecksColumn: FunctionComponent<Props> = ({
checks,
router,
params: {orgID},
rules,
endpoints,
}) => {
const handleClick = () => {
router.push(`/orgs/${orgID}/alerting/checks/new`)
}

const tooltipContents = (
<>
A <strong>Check</strong> is a periodic query that the system
<br />
performs against your time series data
<br />
that will generate a status
</>
)

const noAlertingResourcesExist =
!checks.length && !rules.length && !endpoints.length

const createButton = (
<Button
color={ComponentColor.Primary}
text="Create"
onClick={handleClick}
testID="create-check"
icon={IconFont.Plus}
/>
)

return (
<AlertsColumnHeader title="Checks" onCreate={handleClick}>
<CheckCards checks={checks} />
<AlertsColumnHeader
title="Checks"
createButton={createButton}
questionMarkTooltipContents={tooltipContents}
>
<CheckCards
checks={checks}
showFirstTimeWidget={noAlertingResourcesExist}
/>
</AlertsColumnHeader>
)
}
Expand All @@ -38,9 +74,16 @@ const mstp = (state: AppState) => {
const {
checks: {list: checks},
labels: {list: labels},
rules: {list: rules},
endpoints,
} = state

return {checks, labels: viewableLabels(labels)}
return {
checks,
labels: viewableLabels(labels),
rules,
endpoints: endpoints.list,
}
}

export default connect<StateProps, {}, {}>(
Expand Down
Loading

0 comments on commit 20f717d

Please sign in to comment.