feat(demodata): Polish demo data error reporting (#18107)

* feat(demodata): Add type do demodata notification

* feat(demodata):  do not report dashboard would exceed quota errors

* feat(demodata): notify user of demodata availability error in dashboards

* feat(demodata): Correct error reporting for demodata

* feat(demodata): Add error if demodata bucket is missing
pull/18109/head
Deniz Kusefoglu 2020-05-14 15:55:52 -07:00 committed by GitHub
parent 17f4cc14f2
commit 5102d311b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 23 deletions

View File

@ -88,11 +88,9 @@ export const getDemoDataBucketMembership = ({
dispatch(addBucket(normalizedBucket))
} catch (error) {
const message = `Failed to add demodata bucket ${bucketName}: ${getErrorMessage(
error
)}`
dispatch(notify(demoDataAddBucketFailed(message)))
dispatch(
notify(demoDataAddBucketFailed(bucketName, getErrorMessage(error)))
)
reportError(error, {
name: 'addDemoDataBucket failed in getDemoDataBucketMembership',
@ -116,15 +114,15 @@ export const getDemoDataBucketMembership = ({
fireEvent('demoData_bucketAdded', {demo_dataset: bucketName})
} catch (error) {
const message = `Could not create dashboard for demodata bucket ${bucketName}: ${getErrorMessage(
error
)}`
const errorMessage = getErrorMessage(error)
dispatch(notify(demoDataAddBucketFailed(message)))
dispatch(notify(demoDataAddBucketFailed(bucketName, errorMessage)))
reportError(error, {
name: 'addDemoDataDashboard failed in getDemoDataBucketMembership',
})
if (errorMessage != 'creating dashboard would exceed quota') {
reportError(error, {
name: 'addDemoDataDashboard failed in getDemoDataBucketMembership',
})
}
}
}
@ -134,6 +132,7 @@ export const deleteDemoDataBucketMembership = (
try {
await deleteDemoDataBucketMembershipAJAX(bucket.id)
// an unsuccessful delete membership req can also return 204 to prevent userID sniffing, so need to check that bucket is really unreachable
const resp = await getBucket({bucketID: bucket.id})
if (resp.status === 200) {

View File

@ -40,9 +40,13 @@ export const getDemoDataBucketMembership = async (bucketID: string) => {
})
if (response.status === '200') {
// a failed or successful membership POST to sampledata should return 204
// if sampledata route is not available gateway responds with 200 a correct success code is 204
throw new Error('Could not reach demodata endpoint')
}
if (response.status !== '204') {
throw new Error(response.data)
}
}
export const deleteDemoDataBucketMembership = async (bucketID: string) => {
@ -53,9 +57,13 @@ export const deleteDemoDataBucketMembership = async (bucketID: string) => {
})
if (response.status === '200') {
// a failed or successful membership DELETE to sampledata should return 204
// if sampledata route is not available gateway responds with 200 a correct success code is 204
throw new Error('Could not reach demodata endpoint')
}
if (response.status !== '204') {
throw new Error(response.data)
}
} catch (error) {
console.error(error)
throw error

View File

@ -6,7 +6,7 @@ export const isDemoDataAvailabilityError = (
errorCode: string,
errorMessage: string
): boolean => {
if (!CLOUD || isFlagEnabled('demodata')) {
if (!CLOUD) {
return false
}
@ -17,3 +17,18 @@ export const isDemoDataAvailabilityError = (
}
return false
}
export const demoDataError = (orgID: string) => {
if (isFlagEnabled('demodata')) {
return {
message:
'It looks like this query requires a demo data bucket to be available. You can add demodata buckets on the buckets tab',
linkText: 'Go to buckets',
link: `/orgs/${orgID}/load-data/buckets`,
}
}
return {
message:
'Demo data buckets are temporarily unavailable. Please try again later.',
}
}

View File

@ -28,9 +28,17 @@ import {buildVarsOption} from 'src/variables/utils/buildVarsOption'
import 'intersection-observer'
import {getAll} from 'src/resources/selectors'
import {getOrgIDFromBuckets} from 'src/timeMachine/actions/queries'
import {
isDemoDataAvailabilityError,
demoDataError,
} from 'src/cloud/utils/demoDataErrors'
// Constants
import {rateLimitReached, resultTooLarge} from 'src/shared/copy/notifications'
import {
rateLimitReached,
resultTooLarge,
demoDataAvailability,
} from 'src/shared/copy/notifications'
import {TIME_RANGE_START, TIME_RANGE_STOP} from 'src/variables/constants'
// Actions
@ -233,6 +241,9 @@ class TimeSeries extends Component<Props & WithRouterProps, State> {
for (const result of results) {
if (result.type === 'UNKNOWN_ERROR') {
if (isDemoDataAvailabilityError(result.code, result.message)) {
notify(demoDataAvailability(demoDataError(this.props.params.orgID)))
}
errorMessage = result.message
throw new Error(result.message)
}

View File

@ -452,9 +452,12 @@ export const getBucketFailed = (
// Demodata buckets
export const demoDataAddBucketFailed = (error: string): Notification => ({
export const demoDataAddBucketFailed = (
bucketName: string,
message: string
): Notification => ({
...defaultErrorNotification,
message: error,
message: `Could not create dashboard for demodata bucket ${bucketName}: ${message}`,
})
export const demoDataDeleteBucketFailed = (
@ -476,10 +479,15 @@ export const demoDataSucceeded = (
link,
})
export const demoDataSwitchedOff = (): Notification => ({
export const demoDataAvailability = (error: {
message: string
linkText?: string
link?: string
}): Notification => ({
...defaultErrorNotification,
message: `Demo data buckets are temporarily unavailable. Please try again later.`,
...error,
duration: TEN_SECONDS,
type: 'demoDataAvailabilityError',
})
// Limits

View File

@ -18,7 +18,7 @@ import {hydrateVariables} from 'src/variables/actions/thunks'
import {
rateLimitReached,
resultTooLarge,
demoDataSwitchedOff,
demoDataAvailability,
} from 'src/shared/copy/notifications'
// Utils
@ -27,7 +27,10 @@ import fromFlux from 'src/shared/utils/fromFlux'
import {getAllVariables, asAssignment} from 'src/variables/selectors'
import {buildVarsOption} from 'src/variables/utils/buildVarsOption'
import {findNodes} from 'src/shared/utils/ast'
import {isDemoDataAvailabilityError} from 'src/cloud/utils/demoDataErrors'
import {
isDemoDataAvailabilityError,
demoDataError,
} from 'src/cloud/utils/demoDataErrors'
// Types
import {CancelBox} from 'src/types/promises'
@ -160,7 +163,9 @@ export const executeQueries = () => async (dispatch, getState: GetState) => {
for (const result of results) {
if (result.type === 'UNKNOWN_ERROR') {
if (isDemoDataAvailabilityError(result.code, result.message)) {
dispatch(notify(demoDataSwitchedOff()))
dispatch(
notify(demoDataAvailability(demoDataError(getOrg(state).id)))
)
}
throw new Error(result.message)