feat(ui): redesign asset & rate limit alerts (#19032)
* feat(ui): update rate limit alert * feat(ui): update to clockface 2.3.0 * feat(ui): update limit alert components * feat(ui): add home page limit alert * feat(ui): replace alert page limit alerts * feat(ui): relace load data limit alerts * feat(ui): replace dashboards limit alerts * feat(ui): replace data explorer limit alerts * feat(ui): replace tasks limit alerts * feat(ui): replace settings limit alerts * fix(ui): prettier * feat(ui): update changelog * fix(ui): update clockface to 2.3.1 and fix tests * fix(ui): change test idpull/19055/head
parent
17391d6924
commit
4df52d0cb4
|
@ -21,6 +21,7 @@
|
|||
1. [19029](https://github.com/influxdata/influxdb/pull/19029): Navigating away from a dashboard cancels all pending queries
|
||||
1. [19003](https://github.com/influxdata/influxdb/pull/19003): Upgrade to Flux v0.74.0
|
||||
1. [19040](https://github.com/influxdata/influxdb/pull/19040): Drop the REPL command from influx CLI
|
||||
1. [19032](https://github.com/influxdata/influxdb/pull/19032): Redesign asset & rate limit alerts
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
@ -802,12 +802,12 @@ describe('DataExplorer', () => {
|
|||
cy.getByTestID('raw-data--toggle').click()
|
||||
|
||||
cy.get('.time-machine--view').within(() => {
|
||||
cy.get('.cf-dapper-scrollbars--thumb-y') // TODO(zoe): replace with test ids https://github.com/influxdata/clockface/issues/507
|
||||
cy.getByTestID('rawdata-table--scrollbar--thumb-y')
|
||||
.trigger('mousedown', {force: true})
|
||||
.trigger('mousemove', {clientY: 5000})
|
||||
.trigger('mouseup')
|
||||
|
||||
cy.get('.cf-dapper-scrollbars--thumb-x') // TODO(zoe): replace with test ids https://github.com/influxdata/clockface/issues/507
|
||||
cy.getByTestID('rawdata-table--scrollbar--thumb-x')
|
||||
.trigger('mousedown', {force: true})
|
||||
.trigger('mousemove', {clientX: 1000})
|
||||
.trigger('mouseup')
|
||||
|
@ -831,7 +831,7 @@ describe('DataExplorer', () => {
|
|||
cy.getByTestID(`view-type--table`).click()
|
||||
|
||||
cy.get('.time-machine--view').within(() => {
|
||||
cy.get('.cf-dapper-scrollbars--thumb-y') // TODO(zoe): replace with test ids https://github.com/influxdata/clockface/issues/507
|
||||
cy.getByTestID('dapper-scrollbars--thumb-y')
|
||||
.trigger('mousedown', {force: true})
|
||||
.trigger('mousemove', {clientY: 5000})
|
||||
.trigger('mouseup')
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
"webpack-merge": "^4.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@influxdata/clockface": "2.2.0",
|
||||
"@influxdata/clockface": "2.3.1",
|
||||
"@influxdata/flux": "^0.5.1",
|
||||
"@influxdata/flux-lsp-browser": "^0.5.11",
|
||||
"@influxdata/giraffe": "0.23.0",
|
||||
|
@ -198,4 +198,4 @@
|
|||
"use-persisted-state": "^0.3.0",
|
||||
"webpack-bundle-analyzer": "^3.6.0"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ import EventTable from 'src/eventViewer/components/EventTable'
|
|||
import AlertHistoryControls from 'src/alerting/components/AlertHistoryControls'
|
||||
import AlertHistoryQueryParams from 'src/alerting/components/AlertHistoryQueryParams'
|
||||
import GetResources from 'src/resources/components/GetResources'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
|
||||
// Constants
|
||||
import {
|
||||
|
@ -80,7 +80,7 @@ const AlertHistoryIndex: FC<Props> = ({
|
|||
title="Check Statuses"
|
||||
testID="alert-history-title"
|
||||
/>
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
<Page.ControlBar fullWidth={true}>
|
||||
<AlertHistoryQueryParams
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// Libraries
|
||||
import React, {FunctionComponent, useState} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {Switch, Route} from 'react-router-dom'
|
||||
|
||||
//Components
|
||||
|
@ -9,9 +8,8 @@ import ChecksColumn from 'src/checks/components/ChecksColumn'
|
|||
import RulesColumn from 'src/notifications/rules/components/RulesColumn'
|
||||
import EndpointsColumn from 'src/notifications/endpoints/components/EndpointsColumn'
|
||||
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
|
||||
import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
import GetResources from 'src/resources/components/GetResources'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import NewThresholdCheckEO from 'src/checks/components/NewThresholdCheckEO'
|
||||
import NewDeadmanCheckEO from 'src/checks/components/NewDeadmanCheckEO'
|
||||
import EditCheckEO from 'src/checks/components/EditCheckEO'
|
||||
|
@ -22,28 +20,15 @@ import EditEndpointOverlay from 'src/notifications/endpoints/components/EditEndp
|
|||
|
||||
// Utils
|
||||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
import {
|
||||
extractMonitoringLimitStatus,
|
||||
extractLimitedMonitoringResources,
|
||||
} from 'src/cloud/utils/limits'
|
||||
|
||||
// Types
|
||||
import {AppState, ResourceType} from 'src/types'
|
||||
import {LimitStatus} from 'src/cloud/actions/limits'
|
||||
import {ResourceType} from 'src/types'
|
||||
|
||||
const alertsPath = '/orgs/:orgID/alerting'
|
||||
|
||||
interface StateProps {
|
||||
limitStatus: LimitStatus
|
||||
limitedResources: string
|
||||
}
|
||||
|
||||
type ActiveColumn = 'checks' | 'endpoints' | 'rules'
|
||||
|
||||
const AlertingIndex: FunctionComponent<StateProps> = ({
|
||||
limitStatus,
|
||||
limitedResources,
|
||||
}) => {
|
||||
const AlertingIndex: FunctionComponent = () => {
|
||||
const [activeColumn, setActiveColumn] = useState<ActiveColumn>('checks')
|
||||
|
||||
const pageContentsClassName = `alerting-index alerting-index__${activeColumn}`
|
||||
|
@ -57,7 +42,7 @@ const AlertingIndex: FunctionComponent<StateProps> = ({
|
|||
<Page titleTag={pageTitleSuffixer(['Alerts'])}>
|
||||
<Page.Header fullWidth={true} testID="alerts-page--header">
|
||||
<Page.Title title="Alerts" />
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
<Page.Contents
|
||||
fullWidth={true}
|
||||
|
@ -66,11 +51,6 @@ const AlertingIndex: FunctionComponent<StateProps> = ({
|
|||
>
|
||||
<GetResources resources={[ResourceType.Labels, ResourceType.Buckets]}>
|
||||
<GetAssetLimits>
|
||||
<AssetLimitAlert
|
||||
resourceName={limitedResources}
|
||||
limitStatus={limitStatus}
|
||||
className="load-data--asset-alert"
|
||||
/>
|
||||
<SelectGroup
|
||||
className="alerting-index--selector"
|
||||
shape={ButtonShape.StretchToFit}
|
||||
|
@ -152,11 +132,4 @@ const AlertingIndex: FunctionComponent<StateProps> = ({
|
|||
)
|
||||
}
|
||||
|
||||
const mstp = ({cloud: {limits}}: AppState) => {
|
||||
return {
|
||||
limitStatus: extractMonitoringLimitStatus(limits),
|
||||
limitedResources: extractLimitedMonitoringResources(limits),
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mstp)(AlertingIndex)
|
||||
export default AlertingIndex
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
// Libraries
|
||||
import React, {FC, ReactChild, useState} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
// Types
|
||||
import {ResourceType} from 'src/types'
|
||||
import {AppState, ResourceType} from 'src/types'
|
||||
import {LimitStatus} from 'src/cloud/actions/limits'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -17,13 +19,17 @@ import {
|
|||
QuestionMarkTooltip,
|
||||
ComponentColor,
|
||||
} from '@influxdata/clockface'
|
||||
import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert'
|
||||
|
||||
// Utils
|
||||
import {extractMonitoringLimitStatus} from 'src/cloud/utils/limits'
|
||||
|
||||
type ColumnTypes =
|
||||
| ResourceType.NotificationRules
|
||||
| ResourceType.NotificationEndpoints
|
||||
| ResourceType.Checks
|
||||
|
||||
interface Props {
|
||||
interface OwnProps {
|
||||
type: ColumnTypes
|
||||
title: string
|
||||
createButton: JSX.Element
|
||||
|
@ -31,10 +37,15 @@ interface Props {
|
|||
children: (searchTerm: string) => ReactChild
|
||||
}
|
||||
|
||||
const AlertsColumnHeader: FC<Props> = ({
|
||||
interface StateProps {
|
||||
limitStatus: LimitStatus
|
||||
}
|
||||
|
||||
const AlertsColumnHeader: FC<OwnProps & StateProps> = ({
|
||||
type,
|
||||
children,
|
||||
title,
|
||||
limitStatus,
|
||||
createButton,
|
||||
questionMarkTooltipContents,
|
||||
}) => {
|
||||
|
@ -75,11 +86,20 @@ const AlertsColumnHeader: FC<Props> = ({
|
|||
autoHide={true}
|
||||
style={{width: '100%', height: '100%'}}
|
||||
>
|
||||
<div className="alerting-index--list">{children(searchTerm)}</div>
|
||||
<div className="alerting-index--list">
|
||||
{children(searchTerm)}
|
||||
<AssetLimitAlert resourceName={title} limitStatus={limitStatus} />
|
||||
</div>
|
||||
</DapperScrollbars>
|
||||
</div>
|
||||
</Panel>
|
||||
)
|
||||
}
|
||||
|
||||
export default AlertsColumnHeader
|
||||
const mstp = ({cloud: {limits}}: AppState) => {
|
||||
return {
|
||||
limitStatus: extractMonitoringLimitStatus(limits),
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mstp)(AlertsColumnHeader)
|
||||
|
|
|
@ -102,11 +102,6 @@ class BucketsTab extends PureComponent<Props, State> {
|
|||
|
||||
return (
|
||||
<>
|
||||
<AssetLimitAlert
|
||||
resourceName="buckets"
|
||||
limitStatus={limitStatus}
|
||||
className="load-data--asset-alert"
|
||||
/>
|
||||
<TabbedPageHeader
|
||||
childrenLeft={leftHeaderItems}
|
||||
childrenRight={rightHeaderItems}
|
||||
|
@ -136,6 +131,11 @@ class BucketsTab extends PureComponent<Props, State> {
|
|||
/>
|
||||
)}
|
||||
</FilterBuckets>
|
||||
<AssetLimitAlert
|
||||
resourceName="buckets"
|
||||
limitStatus={limitStatus}
|
||||
className="load-data--asset-alert"
|
||||
/>
|
||||
</Grid.Column>
|
||||
<Grid.Column
|
||||
widthXS={Columns.Twelve}
|
||||
|
|
|
@ -11,22 +11,15 @@ import BucketsTab from 'src/buckets/components/BucketsTab'
|
|||
import GetResources from 'src/resources/components/GetResources'
|
||||
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
|
||||
import LimitChecker from 'src/cloud/components/LimitChecker'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
import LineProtocolWizard from 'src/dataLoaders/components/lineProtocolWizard/LineProtocolWizard'
|
||||
import CollectorsWizard from 'src/dataLoaders/components/collectorsWizard/CollectorsWizard'
|
||||
import UpdateBucketOverlay from 'src/buckets/components/UpdateBucketOverlay'
|
||||
import RenameBucketOverlay from 'src/buckets/components/RenameBucketOverlay'
|
||||
import CreateScraperOverlay from 'src/scrapers/components/CreateScraperOverlay'
|
||||
import DeleteDataOverlay from 'src/shared/components/DeleteDataOverlay'
|
||||
import {
|
||||
FlexBox,
|
||||
FlexDirection,
|
||||
JustifyContent,
|
||||
Page,
|
||||
} from '@influxdata/clockface'
|
||||
import {Page} from '@influxdata/clockface'
|
||||
|
||||
// Utils
|
||||
import {extractRateLimitResources} from 'src/cloud/utils/limits'
|
||||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
|
||||
|
@ -38,7 +31,6 @@ import {AppState, Organization, ResourceType} from 'src/types'
|
|||
|
||||
interface StateProps {
|
||||
org: Organization
|
||||
limitedResources: string[]
|
||||
}
|
||||
|
||||
const bucketsPath = `/${ORGS}/${ORG_ID}/load-data/${BUCKETS}/${BUCKET_ID}`
|
||||
|
@ -53,14 +45,6 @@ class BucketsIndex extends Component<StateProps> {
|
|||
<Page titleTag={pageTitleSuffixer(['Buckets', 'Load Data'])}>
|
||||
<LimitChecker>
|
||||
<LoadDataHeader />
|
||||
<FlexBox
|
||||
direction={FlexDirection.Row}
|
||||
justifyContent={JustifyContent.Center}
|
||||
>
|
||||
{this.isCardinalityExceeded && (
|
||||
<RateLimitAlert className="load-data--rate-alert" />
|
||||
)}
|
||||
</FlexBox>
|
||||
<LoadDataTabbedPage activeTab="buckets" orgID={org.id}>
|
||||
<GetResources
|
||||
resources={[
|
||||
|
@ -102,22 +86,12 @@ class BucketsIndex extends Component<StateProps> {
|
|||
</>
|
||||
)
|
||||
}
|
||||
|
||||
private get isCardinalityExceeded(): boolean {
|
||||
const {limitedResources} = this.props
|
||||
|
||||
return limitedResources.includes('cardinality')
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const {
|
||||
cloud: {limits},
|
||||
} = state
|
||||
const org = getOrg(state)
|
||||
const limitedResources = extractRateLimitResources(limits)
|
||||
|
||||
return {org, limitedResources}
|
||||
return {org}
|
||||
}
|
||||
|
||||
export default connect<StateProps, {}, {}>(mstp, null)(BucketsIndex)
|
||||
|
|
|
@ -1,63 +1,61 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import React, {FC} from 'react'
|
||||
|
||||
// Components
|
||||
import {
|
||||
FlexBox,
|
||||
FlexDirection,
|
||||
AlignItems,
|
||||
ComponentSize,
|
||||
IconFont,
|
||||
ComponentColor,
|
||||
Alert,
|
||||
JustifyContent,
|
||||
Gradients,
|
||||
InfluxColors,
|
||||
GradientBox,
|
||||
Panel,
|
||||
Heading,
|
||||
HeadingElement,
|
||||
AlignItems,
|
||||
} from '@influxdata/clockface'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
|
||||
// Constants
|
||||
import {CLOUD} from 'src/shared/constants'
|
||||
|
||||
// Types
|
||||
import {LimitStatus} from 'src/cloud/actions/limits'
|
||||
import CheckoutButton from 'src/cloud/components/CheckoutButton'
|
||||
|
||||
interface Props {
|
||||
resourceName: string
|
||||
limitStatus: LimitStatus
|
||||
resourceName: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
export default class AssetLimitAlert extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {limitStatus, resourceName, className} = this.props
|
||||
|
||||
if (CLOUD && limitStatus === LimitStatus.EXCEEDED) {
|
||||
return (
|
||||
<FlexBox
|
||||
direction={FlexDirection.Column}
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Large}
|
||||
stretchToFitWidth={true}
|
||||
className={className}
|
||||
>
|
||||
<Alert icon={IconFont.Cloud} color={ComponentColor.Primary}>
|
||||
const AssetLimitAlert: FC<Props> = ({limitStatus, resourceName, className}) => {
|
||||
if (CLOUD && limitStatus === LimitStatus.EXCEEDED) {
|
||||
return (
|
||||
<GradientBox
|
||||
borderGradient={Gradients.MiyazakiSky}
|
||||
borderColor={InfluxColors.Raven}
|
||||
className={className}
|
||||
>
|
||||
<Panel backgroundColor={InfluxColors.Raven} className="asset-alert">
|
||||
<Panel.Header>
|
||||
<Heading element={HeadingElement.H4}>
|
||||
Need more {resourceName}?
|
||||
</Heading>
|
||||
</Panel.Header>
|
||||
<Panel.Body className="asset-alert--contents">
|
||||
<FlexBox
|
||||
alignItems={AlignItems.Center}
|
||||
direction={FlexDirection.Row}
|
||||
justifyContent={JustifyContent.SpaceBetween}
|
||||
margin={ComponentSize.Medium}
|
||||
justifyContent={JustifyContent.FlexEnd}
|
||||
alignItems={AlignItems.FlexEnd}
|
||||
stretchToFitHeight={true}
|
||||
>
|
||||
<div>
|
||||
{`Hey there, looks like you have reached the maximum number of
|
||||
${resourceName} you can create as part of your plan.`}
|
||||
<br />
|
||||
</div>
|
||||
<CheckoutButton />
|
||||
<CloudUpgradeButton buttonText={`Get more ${resourceName}`} />
|
||||
</FlexBox>
|
||||
</Alert>
|
||||
</FlexBox>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
</Panel.Body>
|
||||
</Panel>
|
||||
</GradientBox>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
export default AssetLimitAlert
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
import React, {FunctionComponent} from 'react'
|
||||
|
||||
// Components
|
||||
import {FeatureFlag} from 'src/shared/utils/featureFlag'
|
||||
import {
|
||||
Button,
|
||||
ComponentColor,
|
||||
ComponentSize,
|
||||
FlexBox,
|
||||
FlexDirection,
|
||||
JustifyContent,
|
||||
} from '@influxdata/clockface'
|
||||
|
||||
// Constants
|
||||
import {CLOUD_CHECKOUT_PATH, CLOUD_URL} from 'src/shared/constants'
|
||||
|
||||
const CheckoutButton: FunctionComponent<{}> = () => {
|
||||
const checkoutURL = `${CLOUD_URL}${CLOUD_CHECKOUT_PATH}`
|
||||
const onClick = () => {
|
||||
window.open(checkoutURL, '_self')
|
||||
}
|
||||
|
||||
return (
|
||||
<FeatureFlag name="cloudBilling">
|
||||
<FlexBox
|
||||
direction={FlexDirection.Row}
|
||||
justifyContent={JustifyContent.SpaceAround}
|
||||
margin={ComponentSize.Small}
|
||||
>
|
||||
<div>Want to remove these limits?</div>
|
||||
<Button
|
||||
color={ComponentColor.Primary}
|
||||
onClick={onClick}
|
||||
text="Upgrade Now"
|
||||
size={ComponentSize.Small}
|
||||
/>
|
||||
</FlexBox>
|
||||
</FeatureFlag>
|
||||
)
|
||||
}
|
||||
|
||||
export default CheckoutButton
|
|
@ -1,6 +1,7 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import React, {FC} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components
|
||||
import {
|
||||
|
@ -9,10 +10,12 @@ import {
|
|||
AlignItems,
|
||||
ComponentSize,
|
||||
IconFont,
|
||||
ComponentColor,
|
||||
Alert,
|
||||
JustifyContent,
|
||||
Gradients,
|
||||
InfluxColors,
|
||||
BannerPanel,
|
||||
} from '@influxdata/clockface'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
|
||||
// Utils
|
||||
import {
|
||||
|
@ -26,7 +29,6 @@ import {CLOUD} from 'src/shared/constants'
|
|||
// Types
|
||||
import {AppState} from 'src/types'
|
||||
import {LimitStatus} from 'src/cloud/actions/limits'
|
||||
import CheckoutButton from 'src/cloud/components/CheckoutButton'
|
||||
|
||||
interface StateProps {
|
||||
resources: string[]
|
||||
|
@ -37,65 +39,58 @@ interface OwnProps {
|
|||
}
|
||||
type Props = StateProps & OwnProps
|
||||
|
||||
class RateLimitAlert extends PureComponent<Props> {
|
||||
public render() {
|
||||
const {status, className} = this.props
|
||||
const RateLimitAlert: FC<Props> = ({status, className, resources}) => {
|
||||
const rateLimitAlertClass = classnames('rate-alert', {
|
||||
[`${className}`]: className,
|
||||
})
|
||||
|
||||
if (CLOUD && status === LimitStatus.EXCEEDED) {
|
||||
return (
|
||||
<FlexBox
|
||||
direction={FlexDirection.Column}
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Large}
|
||||
stretchToFitWidth={true}
|
||||
className={className}
|
||||
if (
|
||||
CLOUD &&
|
||||
status === LimitStatus.EXCEEDED &&
|
||||
resources.includes('cardinality')
|
||||
) {
|
||||
return (
|
||||
<FlexBox
|
||||
direction={FlexDirection.Column}
|
||||
alignItems={AlignItems.Center}
|
||||
margin={ComponentSize.Large}
|
||||
className={rateLimitAlertClass}
|
||||
>
|
||||
<BannerPanel
|
||||
size={ComponentSize.ExtraSmall}
|
||||
gradient={Gradients.PolarExpress}
|
||||
icon={IconFont.Cloud}
|
||||
hideMobileIcon={true}
|
||||
textColor={InfluxColors.Yeti}
|
||||
>
|
||||
<Alert icon={IconFont.Cloud} color={ComponentColor.Primary}>
|
||||
<div className="rate-alert--content">
|
||||
<span>
|
||||
You've reached the maximum{' '}
|
||||
<a
|
||||
href="https://v2.docs.influxdata.com/v2.0/reference/glossary/#series-cardinality"
|
||||
target="_blank"
|
||||
>
|
||||
series cardinality
|
||||
</a>{' '}
|
||||
available in your plan. Need to write more data?
|
||||
</span>
|
||||
<FlexBox
|
||||
alignItems={AlignItems.Center}
|
||||
direction={FlexDirection.Row}
|
||||
justifyContent={JustifyContent.SpaceBetween}
|
||||
margin={ComponentSize.Medium}
|
||||
justifyContent={JustifyContent.Center}
|
||||
className="rate-alert--button"
|
||||
>
|
||||
<div>
|
||||
{this.message}
|
||||
<br />
|
||||
</div>
|
||||
<CheckoutButton />
|
||||
<CloudUpgradeButton />
|
||||
</FlexBox>
|
||||
</Alert>
|
||||
</FlexBox>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
</div>
|
||||
</BannerPanel>
|
||||
</FlexBox>
|
||||
)
|
||||
}
|
||||
|
||||
private get message(): string {
|
||||
return `Hey there, it looks like you have exceeded your plan's ${this.resourceName} limits.${this.additionalMessage}`
|
||||
if (CLOUD) {
|
||||
return <CloudUpgradeButton />
|
||||
}
|
||||
|
||||
private get additionalMessage(): string {
|
||||
if (this.props.resources.includes('cardinality')) {
|
||||
return ' Your writes will be rejected until resolved.'
|
||||
}
|
||||
|
||||
return ''
|
||||
}
|
||||
|
||||
private get resourceName(): string {
|
||||
const {resources} = this.props
|
||||
|
||||
const renamedResources = resources.map(resource => {
|
||||
if (resource === 'cardinality') {
|
||||
return 'total series'
|
||||
}
|
||||
|
||||
return resource
|
||||
})
|
||||
|
||||
return renamedResources.join(' and ')
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
|
|
|
@ -62,7 +62,7 @@ class DashboardPage extends Component<Props> {
|
|||
autoRefresh={autoRefresh}
|
||||
onManualRefresh={onManualRefresh}
|
||||
/>
|
||||
<RateLimitAlert className="dashboard--rate-alert" />
|
||||
<RateLimitAlert />
|
||||
<VariablesControlBar />
|
||||
<DashboardComponent manualRefresh={manualRefresh} />
|
||||
</HoverTimeProvider>
|
||||
|
|
|
@ -1,19 +1,29 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import memoizeOne from 'memoize-one'
|
||||
|
||||
// Components
|
||||
import DashboardCard from 'src/dashboards/components/dashboard_index/DashboardCard'
|
||||
import {TechnoSpinner} from '@influxdata/clockface'
|
||||
import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert'
|
||||
|
||||
// Selectors
|
||||
import {getSortedResources, SortTypes} from 'src/shared/utils/sort'
|
||||
|
||||
// Types
|
||||
import {Dashboard, RemoteDataState} from 'src/types'
|
||||
import {AppState, Dashboard, RemoteDataState} from 'src/types'
|
||||
import {Sort} from 'src/clockface'
|
||||
import {LimitStatus} from 'src/cloud/actions/limits'
|
||||
|
||||
interface Props {
|
||||
// Utils
|
||||
import {extractDashboardLimits} from 'src/cloud/utils/limits'
|
||||
|
||||
interface StateProps {
|
||||
limitStatus: LimitStatus
|
||||
}
|
||||
|
||||
interface OwnProps {
|
||||
dashboards: Dashboard[]
|
||||
sortKey: string
|
||||
sortDirection: Sort
|
||||
|
@ -21,7 +31,7 @@ interface Props {
|
|||
onFilterChange: (searchTerm: string) => void
|
||||
}
|
||||
|
||||
export default class DashboardCards extends PureComponent<Props> {
|
||||
class DashboardCards extends PureComponent<OwnProps & StateProps> {
|
||||
private _observer
|
||||
private _spinner
|
||||
|
||||
|
@ -110,6 +120,11 @@ export default class DashboardCards extends PureComponent<Props> {
|
|||
onFilterChange={onFilterChange}
|
||||
/>
|
||||
))}
|
||||
<AssetLimitAlert
|
||||
className="dashboards--asset-alert"
|
||||
resourceName="dashboards"
|
||||
limitStatus={this.props.limitStatus}
|
||||
/>
|
||||
</div>
|
||||
{windowSize * pages < dashboards.length && (
|
||||
<div
|
||||
|
@ -123,3 +138,15 @@ export default class DashboardCards extends PureComponent<Props> {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const {
|
||||
cloud: {limits},
|
||||
} = state
|
||||
|
||||
return {
|
||||
limitStatus: extractDashboardLimits(limits),
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mstp)(DashboardCards)
|
||||
|
|
|
@ -13,9 +13,8 @@ import {Page} from '@influxdata/clockface'
|
|||
import SearchWidget from 'src/shared/components/search_widget/SearchWidget'
|
||||
import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
|
||||
import GetAssetLimits from 'src/cloud/components/GetAssetLimits'
|
||||
import AssetLimitAlert from 'src/cloud/components/AssetLimitAlert'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
import ResourceSortDropdown from 'src/shared/components/resource_sort_dropdown/ResourceSortDropdown'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import DashboardImportOverlay from 'src/dashboards/components/DashboardImportOverlay'
|
||||
import CreateFromTemplateOverlay from 'src/templates/components/createFromTemplateOverlay/CreateFromTemplateOverlay'
|
||||
import DashboardExportOverlay from 'src/dashboards/components/DashboardExportOverlay'
|
||||
|
@ -53,8 +52,9 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public render() {
|
||||
const {createDashboard, limitStatus, sortOptions} = this.props
|
||||
const {createDashboard, sortOptions} = this.props
|
||||
const {searchTerm} = this.state
|
||||
|
||||
return (
|
||||
<>
|
||||
<Page
|
||||
|
@ -63,7 +63,7 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
>
|
||||
<Page.Header fullWidth={false}>
|
||||
<Page.Title title="Dashboards" />
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
<Page.ControlBar fullWidth={false}>
|
||||
<Page.ControlBarLeft>
|
||||
|
@ -97,10 +97,6 @@ class DashboardIndex extends PureComponent<Props, State> {
|
|||
scrollable={true}
|
||||
>
|
||||
<GetAssetLimits>
|
||||
<AssetLimitAlert
|
||||
resourceName="dashboards"
|
||||
limitStatus={limitStatus}
|
||||
/>
|
||||
<DashboardsIndexContents
|
||||
searchTerm={searchTerm}
|
||||
onFilterChange={this.handleFilterDashboards}
|
||||
|
|
|
@ -79,15 +79,8 @@ class DashboardsIndexContents extends Component<Props> {
|
|||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const {
|
||||
cloud: {
|
||||
limits: {status},
|
||||
},
|
||||
} = state
|
||||
|
||||
return {
|
||||
dashboards: getAll<Dashboard>(state, ResourceType.Dashboards),
|
||||
limitStatus: status,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import {useDispatch} from 'react-redux'
|
|||
// Components
|
||||
import TimeMachine from 'src/timeMachine/components/TimeMachine'
|
||||
import LimitChecker from 'src/cloud/components/LimitChecker'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
|
||||
// Actions
|
||||
import {setActiveTimeMachine} from 'src/timeMachine/actions'
|
||||
|
@ -28,7 +27,6 @@ const DataExplorer: FC = () => {
|
|||
|
||||
return (
|
||||
<LimitChecker>
|
||||
<RateLimitAlert />
|
||||
<div className="data-explorer">
|
||||
<HoverTimeProvider>
|
||||
<TimeMachine />
|
||||
|
|
|
@ -11,7 +11,7 @@ import ViewTypeDropdown from 'src/timeMachine/components/view_options/ViewTypeDr
|
|||
import GetResources from 'src/resources/components/GetResources'
|
||||
import TimeZoneDropdown from 'src/shared/components/TimeZoneDropdown'
|
||||
import DeleteDataButton from 'src/dataExplorer/components/DeleteDataButton'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
import SaveAsOverlay from 'src/dataExplorer/components/SaveAsOverlay'
|
||||
import DEDeleteDataOverlay from 'src/dataExplorer/components/DeleteDataOverlay'
|
||||
|
||||
|
@ -40,7 +40,7 @@ const DataExplorerPage: FC = () => {
|
|||
<GetResources resources={[ResourceType.Variables]}>
|
||||
<Page.Header fullWidth={true} testID="data-explorer--header">
|
||||
<Page.Title title="Data Explorer" />
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
<Page.ControlBar fullWidth={true}>
|
||||
<Page.ControlBarLeft>
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
import Resources from 'src/me/components/Resources'
|
||||
import Docs from 'src/me/components/Docs'
|
||||
import GettingStarted from 'src/me/components/GettingStarted'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
|
||||
// Utils
|
||||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
|
@ -39,7 +39,7 @@ export class MePage extends PureComponent<Props> {
|
|||
<Page titleTag={pageTitleSuffixer(['Home'])}>
|
||||
<Page.Header fullWidth={false}>
|
||||
<Page.Title title="Getting Started" testID="home-page--header" />
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<Grid>
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
import React, {Component} from 'react'
|
||||
import React, {FC} from 'react'
|
||||
|
||||
// Components
|
||||
import {Page} from '@influxdata/clockface'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
|
||||
class LoadDataHeader extends Component {
|
||||
public render() {
|
||||
return (
|
||||
<Page.Header fullWidth={false} testID="load-data--header">
|
||||
<Page.Title title="Load Data" />
|
||||
<CloudUpgradeButton />
|
||||
</Page.Header>
|
||||
)
|
||||
}
|
||||
const LoadDataHeader: FC = () => {
|
||||
return (
|
||||
<Page.Header fullWidth={false} testID="load-data--header">
|
||||
<Page.Title title="Load Data" />
|
||||
<RateLimitAlert className="load-data--rate-alert" />
|
||||
</Page.Header>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoadDataHeader
|
||||
|
|
|
@ -2,14 +2,14 @@ import React, {Component} from 'react'
|
|||
|
||||
// Components
|
||||
import {Page} from '@influxdata/clockface'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
|
||||
class SettingsHeader extends Component {
|
||||
public render() {
|
||||
return (
|
||||
<Page.Header fullWidth={false}>
|
||||
<Page.Title title="Settings" testID="settings-page--header" />
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,8 +2,15 @@
|
|||
import React, {FC} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {get, find} from 'lodash'
|
||||
import classnames from 'classnames'
|
||||
|
||||
// Components
|
||||
import {
|
||||
LinkButton,
|
||||
ComponentColor,
|
||||
ComponentSize,
|
||||
ButtonShape,
|
||||
} from '@influxdata/clockface'
|
||||
import CloudOnly from 'src/shared/components/cloud/CloudOnly'
|
||||
|
||||
// Constants
|
||||
|
@ -20,17 +27,32 @@ interface StateProps {
|
|||
inView: boolean
|
||||
}
|
||||
|
||||
const CloudUpgradeButton: FC<StateProps> = ({inView}) => {
|
||||
interface OwnProps {
|
||||
className?: string
|
||||
buttonText?: string
|
||||
}
|
||||
|
||||
const CloudUpgradeButton: FC<StateProps & OwnProps> = ({
|
||||
inView,
|
||||
className,
|
||||
buttonText = 'Upgrade Now',
|
||||
}) => {
|
||||
const cloudUpgradeButtonClass = classnames('upgrade-payg--button', {
|
||||
[`${className}`]: className,
|
||||
})
|
||||
|
||||
return (
|
||||
<CloudOnly>
|
||||
{inView && (
|
||||
<a
|
||||
className="cf-button cf-button-sm cf-button-success upgrade-payg--button"
|
||||
<LinkButton
|
||||
className={cloudUpgradeButtonClass}
|
||||
color={ComponentColor.Success}
|
||||
size={ComponentSize.Small}
|
||||
shape={ButtonShape.Default}
|
||||
href={`${CLOUD_URL}${CLOUD_CHECKOUT_PATH}`}
|
||||
target="_self"
|
||||
>
|
||||
Upgrade Now
|
||||
</a>
|
||||
text={buttonText}
|
||||
/>
|
||||
)}
|
||||
</CloudOnly>
|
||||
)
|
||||
|
|
|
@ -1,20 +1,67 @@
|
|||
.dashboard--rate-alert {
|
||||
padding: 0 $page-gutter;
|
||||
width: 100%;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.load-data--rate-alert {
|
||||
padding: 0 $page-gutter;
|
||||
padding-bottom: 16px;
|
||||
max-width: 1608px;
|
||||
}
|
||||
|
||||
.load-data--asset-alert {
|
||||
padding-bottom: 16px;
|
||||
margin-bottom: $cf-marg-d;
|
||||
}
|
||||
|
||||
// Might need to remove this eventually
|
||||
.cf-page-header--fixed {
|
||||
justify-content: space-between;
|
||||
.cf-page-control-bar {
|
||||
+ .rate-alert {
|
||||
margin: 0 $cf-marg-c $cf-marg-c;
|
||||
}
|
||||
}
|
||||
|
||||
.rate-alert--content {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
font-weight: 500;
|
||||
|
||||
.rate-alert--button {
|
||||
margin-top: $cf-marg-b;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-page--title {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.asset-alert {
|
||||
height: 100%;
|
||||
background-position: bottom -20px left -20px;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-image: url('../../assets/images/dashboard-empty--dark.svg');
|
||||
}
|
||||
|
||||
.dashboards--asset-alert {
|
||||
.asset-alert--contents {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a.upgrade-payg--button {
|
||||
@include gradient-diag-up($c-pool, $c-rainforest);
|
||||
}
|
||||
|
||||
@media screen and (min-width: $cf-nav-menu--breakpoint) {
|
||||
.rate-alert {
|
||||
margin-left: $cf-marg-d;
|
||||
}
|
||||
|
||||
.rate-alert--content {
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.rate-alert--button {
|
||||
margin-top: 0;
|
||||
margin-left: $cf-marg-c;
|
||||
}
|
||||
}
|
||||
|
||||
.cf-page-control-bar {
|
||||
+ .rate-alert {
|
||||
margin: 0 $cf-marg-d $cf-marg-c;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ $nav-size: 50px;
|
|||
$nav-breakpoint: 800px;
|
||||
$page-header-size: 66px;
|
||||
$page-max-width: 1608px;
|
||||
$page-gutter: 54px;
|
||||
$page-title-size: 21px;
|
||||
$page-title-weight: 400;
|
||||
$sidebar--width: 50px; //delete this later
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
import AddResourceDropdown from 'src/shared/components/AddResourceDropdown'
|
||||
import SearchWidget from 'src/shared/components/search_widget/SearchWidget'
|
||||
import ResourceSortDropdown from 'src/shared/components/resource_sort_dropdown/ResourceSortDropdown'
|
||||
import CloudUpgradeButton from 'src/shared/components/CloudUpgradeButton'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
|
||||
// Types
|
||||
import {LimitStatus} from 'src/cloud/actions/limits'
|
||||
|
@ -63,7 +63,7 @@ export default class TasksHeader extends PureComponent<Props> {
|
|||
<>
|
||||
<Page.Header fullWidth={false} testID="tasks-page--header">
|
||||
<Page.Title title="Tasks" />
|
||||
<CloudUpgradeButton />
|
||||
<RateLimitAlert />
|
||||
</Page.Header>
|
||||
<Page.ControlBar fullWidth={false}>
|
||||
<Page.ControlBarLeft>
|
||||
|
|
|
@ -113,10 +113,6 @@ class TasksPage extends PureComponent<Props, State> {
|
|||
<Page.Contents fullWidth={false} scrollable={true}>
|
||||
<GetResources resources={[ResourceType.Tasks, ResourceType.Labels]}>
|
||||
<GetAssetLimits>
|
||||
<AssetLimitAlert
|
||||
resourceName="tasks"
|
||||
limitStatus={limitStatus}
|
||||
/>
|
||||
<Filter
|
||||
list={this.filteredTasks}
|
||||
searchTerm={searchTerm}
|
||||
|
@ -147,6 +143,10 @@ class TasksPage extends PureComponent<Props, State> {
|
|||
)}
|
||||
</Filter>
|
||||
{this.hiddenTaskAlert}
|
||||
<AssetLimitAlert
|
||||
resourceName="tasks"
|
||||
limitStatus={limitStatus}
|
||||
/>
|
||||
</GetAssetLimits>
|
||||
</GetResources>
|
||||
</Page.Contents>
|
||||
|
|
|
@ -10,15 +10,9 @@ import LoadDataHeader from 'src/settings/components/LoadDataHeader'
|
|||
import Collectors from 'src/telegrafs/components/Collectors'
|
||||
import GetResources from 'src/resources/components/GetResources'
|
||||
import LimitChecker from 'src/cloud/components/LimitChecker'
|
||||
import RateLimitAlert from 'src/cloud/components/RateLimitAlert'
|
||||
import TelegrafInstructionsOverlay from 'src/telegrafs/components/TelegrafInstructionsOverlay'
|
||||
import CollectorsWizard from 'src/dataLoaders/components/collectorsWizard/CollectorsWizard'
|
||||
import {
|
||||
FlexBox,
|
||||
FlexDirection,
|
||||
JustifyContent,
|
||||
Page,
|
||||
} from '@influxdata/clockface'
|
||||
import {Page} from '@influxdata/clockface'
|
||||
import OverlayHandler, {
|
||||
RouteOverlay,
|
||||
} from 'src/overlays/components/RouteOverlay'
|
||||
|
@ -39,7 +33,6 @@ const TelegrafOutputOverlay = RouteOverlay(
|
|||
)
|
||||
|
||||
// Utils
|
||||
import {extractRateLimitResources} from 'src/cloud/utils/limits'
|
||||
import {pageTitleSuffixer} from 'src/shared/utils/pageTitles'
|
||||
import {getOrg} from 'src/organizations/selectors'
|
||||
|
||||
|
@ -51,7 +44,6 @@ import {ORGS, ORG_ID, TELEGRAFS} from 'src/shared/constants/routes'
|
|||
|
||||
interface StateProps {
|
||||
org: Organization
|
||||
limitedResources: string[]
|
||||
}
|
||||
|
||||
const telegrafsPath = `/${ORGS}/${ORG_ID}/load-data/${TELEGRAFS}`
|
||||
|
@ -66,14 +58,6 @@ class TelegrafsPage extends PureComponent<StateProps> {
|
|||
<Page titleTag={pageTitleSuffixer(['Telegraf', 'Load Data'])}>
|
||||
<LimitChecker>
|
||||
<LoadDataHeader />
|
||||
<FlexBox
|
||||
direction={FlexDirection.Row}
|
||||
justifyContent={JustifyContent.Center}
|
||||
>
|
||||
{this.isCardinalityExceeded && (
|
||||
<RateLimitAlert className="load-data--rate-alert" />
|
||||
)}
|
||||
</FlexBox>
|
||||
<LoadDataTabbedPage activeTab="telegrafs" orgID={org.id}>
|
||||
<GetResources
|
||||
resources={[ResourceType.Buckets, ResourceType.Telegrafs]}
|
||||
|
@ -101,21 +85,11 @@ class TelegrafsPage extends PureComponent<StateProps> {
|
|||
</>
|
||||
)
|
||||
}
|
||||
private get isCardinalityExceeded(): boolean {
|
||||
const {limitedResources} = this.props
|
||||
|
||||
return limitedResources.includes('cardinality')
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = (state: AppState) => {
|
||||
const org = getOrg(state)
|
||||
const {
|
||||
cloud: {limits},
|
||||
} = state
|
||||
const limitedResources = extractRateLimitResources(limits)
|
||||
|
||||
return {org, limitedResources}
|
||||
return {org}
|
||||
}
|
||||
|
||||
export default connect<StateProps>(mstp)(TelegrafsPage)
|
||||
|
|
|
@ -747,10 +747,10 @@
|
|||
debug "^3.1.0"
|
||||
lodash.once "^4.1.1"
|
||||
|
||||
"@influxdata/clockface@2.2.0":
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@influxdata/clockface/-/clockface-2.2.0.tgz#73f09f4832d6b6bad53af029844a11dd6562527e"
|
||||
integrity sha512-pIQPJXjvVgzcryhAjgZPSoC5BRLbQb1sIIY9l6KQCg4DWJkxqFC/sPI7qJItRXd8kiPXbfbHvXGAwqIY+TdWNQ==
|
||||
"@influxdata/clockface@2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@influxdata/clockface/-/clockface-2.3.1.tgz#562a218e62b50ba16cd4a4e1e88b2e335289c595"
|
||||
integrity sha512-NqPaCT/vUOCEnjAekfECAvUS3OiSwHREwG/5YuawCw5EoswcUc9h6sMSo2spPxXQuiVAB4RcsxeX3+hqP6pU7w==
|
||||
|
||||
"@influxdata/flux-lsp-browser@^0.5.11":
|
||||
version "0.5.11"
|
||||
|
|
Loading…
Reference in New Issue