Actually type notifications
parent
a14fdc806d
commit
6ff87be8e0
|
@ -417,7 +417,7 @@ export const getDashboardsNamesAsync = (sourceID: string) => async (
|
|||
}
|
||||
}
|
||||
|
||||
export const getDashboardAsync = (dashboardID: string) => async (
|
||||
export const getDashboardAsync = (dashboardID: number) => async (
|
||||
dispatch
|
||||
): Promise<Dashboard | null> => {
|
||||
try {
|
||||
|
@ -813,7 +813,7 @@ const syncDashboardFromURLQueryParams = (
|
|||
}
|
||||
|
||||
export const getDashboardWithHydratedAndSyncedTempVarsAsync = (
|
||||
dashboardID: string,
|
||||
dashboardID: number,
|
||||
source: Source,
|
||||
router: InjectedRouter,
|
||||
location: Location
|
||||
|
|
|
@ -526,7 +526,7 @@ DashboardPage.propTypes = {
|
|||
sources: arrayOf(shape({})).isRequired,
|
||||
params: shape({
|
||||
sourceID: string.isRequired,
|
||||
dashboardID: string.isRequired,
|
||||
dashboardID: number.isRequired,
|
||||
}).isRequired,
|
||||
location: shape({
|
||||
pathname: string.isRequired,
|
||||
|
|
|
@ -134,7 +134,7 @@ class AlertTabs extends PureComponent<Props, State> {
|
|||
this.setState({services})
|
||||
} catch (error) {
|
||||
this.setState({services: null})
|
||||
this.props.notify(notifyCouldNotRetrieveKapacitorServices(kapacitor))
|
||||
this.props.notify(notifyCouldNotRetrieveKapacitorServices(kapacitor.name))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
// All copy for notifications should be stored here for easy editing
|
||||
// and ensuring stylistic consistency
|
||||
import {Notification} from 'src/types'
|
||||
|
||||
type NotificationExcludingMessage = Pick<
|
||||
Notification,
|
||||
Exclude<keyof Notification, 'message'>
|
||||
>
|
||||
|
||||
import {FIVE_SECONDS, TEN_SECONDS, INFINITE} from 'src/shared/constants/index'
|
||||
import {MAX_RESPONSE_BYTES} from 'src/flux/constants'
|
||||
|
||||
const defaultErrorNotification = {
|
||||
const defaultErrorNotification: NotificationExcludingMessage = {
|
||||
type: 'error',
|
||||
icon: 'alert-triangle',
|
||||
duration: TEN_SECONDS,
|
||||
}
|
||||
|
||||
const defaultSuccessNotification = {
|
||||
const defaultSuccessNotification: NotificationExcludingMessage = {
|
||||
type: 'success',
|
||||
icon: 'checkmark',
|
||||
duration: FIVE_SECONDS,
|
||||
}
|
||||
|
||||
const defaultDeletionNotification = {
|
||||
const defaultDeletionNotification: NotificationExcludingMessage = {
|
||||
type: 'primary',
|
||||
icon: 'trash',
|
||||
duration: FIVE_SECONDS,
|
||||
|
@ -24,209 +30,240 @@ const defaultDeletionNotification = {
|
|||
|
||||
// Misc Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyGenericFail = () => 'Could not communicate with server.'
|
||||
export const notifyGenericFail = (): string =>
|
||||
'Could not communicate with server.'
|
||||
|
||||
export const notifyNewVersion = version => ({
|
||||
export const notifyNewVersion = (version: string): Notification => ({
|
||||
type: 'info',
|
||||
icon: 'cubo-uniform',
|
||||
duration: INFINITE,
|
||||
message: `Welcome to the latest Chronograf${version}. Local settings cleared.`,
|
||||
})
|
||||
|
||||
export const notifyLoadLocalSettingsFailed = error => ({
|
||||
export const notifyLoadLocalSettingsFailed = (error: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Loading local settings failed: ${error}`,
|
||||
})
|
||||
|
||||
export const notifyErrorWithAltText = (type, message) => ({
|
||||
export const notifyErrorWithAltText = (
|
||||
type: string,
|
||||
message: string
|
||||
): Notification => ({
|
||||
type,
|
||||
icon: 'triangle',
|
||||
duration: TEN_SECONDS,
|
||||
message,
|
||||
})
|
||||
|
||||
export const notifyPresentationMode = () => ({
|
||||
export const notifyPresentationMode = (): Notification => ({
|
||||
type: 'primary',
|
||||
icon: 'expand-b',
|
||||
duration: 7500,
|
||||
message: 'Press ESC to exit Presentation Mode.',
|
||||
})
|
||||
|
||||
export const notifyDataWritten = () => ({
|
||||
export const notifyDataWritten = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Data was written successfully.',
|
||||
})
|
||||
|
||||
export const notifyDataWriteFailed = errorMessage => ({
|
||||
export const notifyDataWriteFailed = (errorMessage: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Data write failed: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifySessionTimedOut = () => ({
|
||||
export const notifySessionTimedOut = (): Notification => ({
|
||||
type: 'primary',
|
||||
icon: 'triangle',
|
||||
duration: INFINITE,
|
||||
message: 'Your session has timed out. Log in again to continue.',
|
||||
})
|
||||
|
||||
export const notifyServerError = {
|
||||
export const notifyServerError: Notification = {
|
||||
...defaultErrorNotification,
|
||||
message: 'Internal Server Error. Check API Logs.',
|
||||
}
|
||||
|
||||
export const notifyCouldNotRetrieveKapacitors = sourceID => ({
|
||||
export const notifyCouldNotRetrieveKapacitors = (
|
||||
sourceID: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Internal Server Error. Could not retrieve Kapacitor Connections for source ${sourceID}.`,
|
||||
})
|
||||
|
||||
export const notifyCouldNotRetrieveKapacitorServices = kapacitor => ({
|
||||
export const notifyCouldNotRetrieveKapacitorServices = (
|
||||
kapacitor: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Interanl Server Error. Could not retrieve services for Kapacitor ${kapacitor}`,
|
||||
message: `Internal Server Error. Could not retrieve services for Kapacitor ${kapacitor}`,
|
||||
})
|
||||
|
||||
export const notifyCouldNotDeleteKapacitor = () => ({
|
||||
export const notifyCouldNotDeleteKapacitor = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Internal Server Error. Could not delete Kapacitor Connection.',
|
||||
})
|
||||
|
||||
export const notifyCSVDownloadFailed = () => ({
|
||||
export const notifyCSVDownloadFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Unable to download .CSV file',
|
||||
})
|
||||
|
||||
// Hosts Page Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyUnableToGetHosts = () => ({
|
||||
export const notifyUnableToGetHosts = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Unable to get Hosts.',
|
||||
})
|
||||
|
||||
export const notifyUnableToGetApps = () => ({
|
||||
export const notifyUnableToGetApps = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Unable to get Apps for Hosts.',
|
||||
})
|
||||
|
||||
// InfluxDB Sources Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifySourceCreationSucceeded = sourceName => ({
|
||||
export const notifySourceCreationSucceeded = (
|
||||
sourceName: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'server2',
|
||||
message: `Connected to InfluxDB ${sourceName} successfully.`,
|
||||
})
|
||||
|
||||
export const notifySourceCreationFailed = (sourceName, errorMessage) => ({
|
||||
export const notifySourceCreationFailed = (
|
||||
sourceName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `Unable to connect to InfluxDB ${sourceName}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifySourceUdpated = sourceName => ({
|
||||
export const notifySourceUdpated = (sourceName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'server2',
|
||||
message: `Updated InfluxDB ${sourceName} Connection successfully.`,
|
||||
})
|
||||
|
||||
export const notifySourceUdpateFailed = (sourceName, errorMessage) => ({
|
||||
export const notifySourceUdpateFailed = (
|
||||
sourceName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `Failed to update InfluxDB ${sourceName} Connection: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifySourceDeleted = (sourceName: string) => ({
|
||||
export const notifySourceDeleted = (sourceName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'server2',
|
||||
message: `${sourceName} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifySourceDeleteFailed = sourceName => ({
|
||||
export const notifySourceDeleteFailed = (sourceName: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `There was a problem deleting ${sourceName}.`,
|
||||
})
|
||||
|
||||
export const notifySourceNoLongerAvailable = sourceName =>
|
||||
`Source ${sourceName} is no longer available. Please ensure InfluxDB is running.`
|
||||
export const notifySourceNoLongerAvailable = (
|
||||
sourceName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `Source ${sourceName} is no longer available. Please ensure InfluxDB is running.`,
|
||||
})
|
||||
|
||||
export const notifyNoSourcesAvailable = sourceName =>
|
||||
`Unable to connect to source ${sourceName}. No other sources available.`
|
||||
|
||||
export const notifyUnableToRetrieveSources = () => 'Unable to retrieve sources.'
|
||||
|
||||
export const notifyUnableToConnectSource = sourceName =>
|
||||
`Unable to connect to source ${sourceName}.`
|
||||
|
||||
export const notifyErrorConnectingToSource = errorMessage =>
|
||||
`Unable to connect to InfluxDB source: ${errorMessage}`
|
||||
export const notifyErrorConnectingToSource = (
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'server2',
|
||||
message: `Unable to connect to InfluxDB source: ${errorMessage}`,
|
||||
})
|
||||
|
||||
// Multitenancy User Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyUserRemovedFromAllOrgs = () => ({
|
||||
export const notifyUserRemovedFromAllOrgs = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message:
|
||||
'You have been removed from all organizations. Please contact your administrator.',
|
||||
})
|
||||
|
||||
export const notifyUserRemovedFromCurrentOrg = () => ({
|
||||
export const notifyUserRemovedFromCurrentOrg = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: 'You were removed from your current organization.',
|
||||
})
|
||||
|
||||
export const notifyOrgHasNoSources = () => ({
|
||||
export const notifyOrgHasNoSources = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: 'Organization has no sources configured.',
|
||||
})
|
||||
|
||||
export const notifyUserSwitchedOrgs = (orgName, roleName) => ({
|
||||
export const notifyUserSwitchedOrgs = (
|
||||
orgName: string,
|
||||
roleName: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
type: 'primary',
|
||||
message: `Now logged in to '${orgName}' as '${roleName}'.`,
|
||||
})
|
||||
|
||||
export const notifyOrgIsPrivate = () => ({
|
||||
export const notifyOrgIsPrivate = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message:
|
||||
'This organization is private. To gain access, you must be explicitly added by an administrator.',
|
||||
})
|
||||
|
||||
export const notifyCurrentOrgDeleted = () => ({
|
||||
export const notifyCurrentOrgDeleted = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: 'Your current organization was deleted.',
|
||||
})
|
||||
|
||||
export const notifyJSONFeedFailed = url => ({
|
||||
export const notifyJSONFeedFailed = (url: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Failed to fetch JSON Feed for News Feed from '${url}'`,
|
||||
})
|
||||
|
||||
// Chronograf Admin Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyMappingDeleted = (id, scheme) => ({
|
||||
export const notifyMappingDeleted = (
|
||||
id: string,
|
||||
scheme: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Mapping ${id}/${scheme} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyChronografUserAddedToOrg = (user, organization) =>
|
||||
`${user} has been added to ${organization} successfully.`
|
||||
export const notifyChronografUserAddedToOrg = (
|
||||
user: string,
|
||||
organization: string
|
||||
): string => `${user} has been added to ${organization} successfully.`
|
||||
|
||||
export const notifyChronografUserRemovedFromOrg = (user, organization) =>
|
||||
`${user} has been removed from ${organization} successfully.`
|
||||
export const notifyChronografUserRemovedFromOrg = (
|
||||
user: string,
|
||||
organization: string
|
||||
): string => `${user} has been removed from ${organization} successfully.`
|
||||
|
||||
export const notifyChronografUserUpdated = message => ({
|
||||
export const notifyChronografUserUpdated = (message: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message,
|
||||
})
|
||||
|
||||
export const notifyChronografOrgDeleted = orgName => ({
|
||||
export const notifyChronografOrgDeleted = (orgName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Organization ${orgName} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyChronografUserDeleted = (user, isAbsoluteDelete) => ({
|
||||
export const notifyChronografUserDeleted = (
|
||||
user: string,
|
||||
isAbsoluteDelete: boolean
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${user} has been removed from ${
|
||||
isAbsoluteDelete
|
||||
|
@ -235,7 +272,7 @@ export const notifyChronografUserDeleted = (user, isAbsoluteDelete) => ({
|
|||
}`,
|
||||
})
|
||||
|
||||
export const notifyChronografUserMissingNameAndProvider = () => ({
|
||||
export const notifyChronografUserMissingNameAndProvider = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
type: 'warning',
|
||||
message: 'User must have a Name and Provider.',
|
||||
|
@ -243,220 +280,238 @@ export const notifyChronografUserMissingNameAndProvider = () => ({
|
|||
|
||||
// InfluxDB Admin Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyDBUserCreated = () => ({
|
||||
export const notifyDBUserCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User created successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserCreationFailed = errorMessage =>
|
||||
export const notifyDBUserCreationFailed = (errorMessage: string): string =>
|
||||
`Failed to create User: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserDeleted = userName => ({
|
||||
export const notifyDBUserDeleted = (userName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `User "${userName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDBUserDeleteFailed = errorMessage =>
|
||||
export const notifyDBUserDeleteFailed = (errorMessage: string): string =>
|
||||
`Failed to delete User: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserPermissionsUpdated = () => ({
|
||||
export const notifyDBUserPermissionsUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User Permissions updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserPermissionsUpdateFailed = errorMessage =>
|
||||
`Failed to update User Permissions: ${errorMessage}`
|
||||
export const notifyDBUserPermissionsUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update User Permissions: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserRolesUpdated = () => ({
|
||||
export const notifyDBUserRolesUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User Roles updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserRolesUpdateFailed = errorMessage =>
|
||||
export const notifyDBUserRolesUpdateFailed = (errorMessage: string): string =>
|
||||
`Failed to update User Roles: ${errorMessage}`
|
||||
|
||||
export const notifyDBUserPasswordUpdated = () => ({
|
||||
export const notifyDBUserPasswordUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'User Password updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBUserPasswordUpdateFailed = errorMessage =>
|
||||
`Failed to update User Password: ${errorMessage}`
|
||||
export const notifyDBUserPasswordUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update User Password: ${errorMessage}`
|
||||
|
||||
export const notifyDatabaseCreated = () => ({
|
||||
export const notifyDatabaseCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Database created successfully.',
|
||||
})
|
||||
|
||||
export const notifyDBCreationFailed = errorMessage =>
|
||||
export const notifyDBCreationFailed = (errorMessage: string): string =>
|
||||
`Failed to create Database: ${errorMessage}`
|
||||
|
||||
export const notifyDBDeleted = databaseName => ({
|
||||
export const notifyDBDeleted = (databaseName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Database "${databaseName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDBDeleteFailed = errorMessage =>
|
||||
export const notifyDBDeleteFailed = (errorMessage: string): string =>
|
||||
`Failed to delete Database: ${errorMessage}`
|
||||
|
||||
export const notifyRoleCreated = () => ({
|
||||
export const notifyRoleCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Role created successfully.',
|
||||
})
|
||||
|
||||
export const notifyRoleCreationFailed = errorMessage =>
|
||||
export const notifyRoleCreationFailed = (errorMessage: string): string =>
|
||||
`Failed to create Role: ${errorMessage}`
|
||||
|
||||
export const notifyRoleDeleted = roleName => ({
|
||||
export const notifyRoleDeleted = (roleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Role "${roleName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyRoleDeleteFailed = errorMessage =>
|
||||
export const notifyRoleDeleteFailed = (errorMessage: string): string =>
|
||||
`Failed to delete Role: ${errorMessage}`
|
||||
|
||||
export const notifyRoleUsersUpdated = () => ({
|
||||
export const notifyRoleUsersUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Role Users updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyRoleUsersUpdateFailed = errorMessage =>
|
||||
export const notifyRoleUsersUpdateFailed = (errorMessage: string): string =>
|
||||
`Failed to update Role Users: ${errorMessage}`
|
||||
|
||||
export const notifyRolePermissionsUpdated = () => ({
|
||||
export const notifyRolePermissionsUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Role Permissions updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyRolePermissionsUpdateFailed = errorMessage =>
|
||||
`Failed to update Role Permissions: ${errorMessage}`
|
||||
export const notifyRolePermissionsUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update Role Permissions: ${errorMessage}`
|
||||
|
||||
export const notifyRetentionPolicyCreated = () => ({
|
||||
export const notifyRetentionPolicyCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Retention Policy created successfully.',
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyCreationError = () => ({
|
||||
export const notifyRetentionPolicyCreationError = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Failed to create Retention Policy. Please check name and duration.',
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyCreationFailed = errorMessage =>
|
||||
`Failed to create Retention Policy: ${errorMessage}`
|
||||
export const notifyRetentionPolicyCreationFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to create Retention Policy: ${errorMessage}`
|
||||
|
||||
export const notifyRetentionPolicyDeleted = rpName => ({
|
||||
export const notifyRetentionPolicyDeleted = (rpName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Retention Policy "${rpName}" deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyDeleteFailed = errorMessage =>
|
||||
`Failed to delete Retention Policy: ${errorMessage}`
|
||||
export const notifyRetentionPolicyDeleteFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to delete Retention Policy: ${errorMessage}`
|
||||
|
||||
export const notifyRetentionPolicyUpdated = () => ({
|
||||
export const notifyRetentionPolicyUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Retention Policy updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyUpdateFailed = errorMessage =>
|
||||
`Failed to update Retention Policy: ${errorMessage}`
|
||||
export const notifyRetentionPolicyUpdateFailed = (
|
||||
errorMessage: string
|
||||
): string => `Failed to update Retention Policy: ${errorMessage}`
|
||||
|
||||
export const notifyQueriesError = errorMessage => ({
|
||||
export const notifyQueriesError = (errorMessage: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
errorMessage,
|
||||
message: errorMessage,
|
||||
})
|
||||
|
||||
export const notifyRetentionPolicyCantHaveEmptyFields = () => ({
|
||||
export const notifyRetentionPolicyCantHaveEmptyFields = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Fields cannot be empty.',
|
||||
})
|
||||
|
||||
export const notifyDatabaseDeleteConfirmationRequired = databaseName => ({
|
||||
export const notifyDatabaseDeleteConfirmationRequired = (
|
||||
databaseName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Type "DELETE ${databaseName}" to confirm. This action cannot be undone.`,
|
||||
})
|
||||
|
||||
export const notifyDBUserNamePasswordInvalid = () => ({
|
||||
export const notifyDBUserNamePasswordInvalid = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Username and/or Password too short.',
|
||||
})
|
||||
|
||||
export const notifyRoleNameInvalid = () => ({
|
||||
export const notifyRoleNameInvalid = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Role name is too short.',
|
||||
})
|
||||
|
||||
export const notifyDatabaseNameInvalid = () => ({
|
||||
export const notifyDatabaseNameInvalid = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Database name cannot be blank.',
|
||||
})
|
||||
|
||||
export const notifyDatabaseNameAlreadyExists = () => ({
|
||||
export const notifyDatabaseNameAlreadyExists = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'A Database by this name already exists.',
|
||||
})
|
||||
|
||||
// Dashboard Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyTempVarAlreadyExists = tempVarName => ({
|
||||
export const notifyTempVarAlreadyExists = (
|
||||
tempVarName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Variable '${tempVarName}' already exists. Please enter a new value.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardNotFound = dashboardID => ({
|
||||
export const notifyDashboardNotFound = (dashboardID: number): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${dashboardID} could not be found`,
|
||||
})
|
||||
|
||||
export const notifyDashboardDeleted = name => ({
|
||||
export const notifyDashboardDeleted = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${name} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardExported = name => ({
|
||||
export const notifyDashboardExported = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${name} exported successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardExportFailed = (name, errorMessage) => ({
|
||||
export const notifyDashboardExportFailed = (
|
||||
name: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: `Failed to export Dashboard ${name}: ${errorMessage}.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardImported = name => ({
|
||||
export const notifyDashboardImported = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `Dashboard ${name} imported successfully.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardImportFailed = (fileName, errorMessage) => ({
|
||||
export const notifyDashboardImportFailed = (
|
||||
fileName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
duration: INFINITE,
|
||||
message: `Failed to import Dashboard from file ${fileName}: ${errorMessage}.`,
|
||||
})
|
||||
|
||||
export const notifyDashboardDeleteFailed = (name, errorMessage) =>
|
||||
`Failed to delete Dashboard ${name}: ${errorMessage}.`
|
||||
export const notifyDashboardDeleteFailed = (
|
||||
name: string,
|
||||
errorMessage: string
|
||||
): string => `Failed to delete Dashboard ${name}: ${errorMessage}.`
|
||||
|
||||
export const notifyCellAdded = name => ({
|
||||
export const notifyCellAdded = (name: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
duration: 1900,
|
||||
message: `Added "${name}" to dashboard.`,
|
||||
})
|
||||
|
||||
export const notifyCellDeleted = name => ({
|
||||
export const notifyCellDeleted = (name: string): Notification => ({
|
||||
...defaultDeletionNotification,
|
||||
icon: 'dash-h',
|
||||
duration: 1900,
|
||||
message: `Deleted "${name}" from dashboard.`,
|
||||
})
|
||||
|
||||
export const notifyBuilderDisabled = () => ({
|
||||
export const notifyBuilderDisabled = (): Notification => ({
|
||||
type: 'info',
|
||||
icon: 'graphline',
|
||||
duration: 7500,
|
||||
|
@ -465,249 +520,280 @@ export const notifyBuilderDisabled = () => ({
|
|||
|
||||
// Template Variables & URL Queries
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyInvalidTempVarValueInURLQuery = ({key, value}) => ({
|
||||
interface KeyValueString {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
export const notifyInvalidTempVarValueInURLQuery = ({
|
||||
key,
|
||||
value,
|
||||
}: KeyValueString): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Invalid URL query value of '${value}' supplied for template variable '${key}'.`,
|
||||
})
|
||||
|
||||
export const notifyInvalidTimeRangeValueInURLQuery = () => ({
|
||||
export const notifyInvalidTimeRangeValueInURLQuery = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Invalid URL query value supplied for lower or upper time range.`,
|
||||
})
|
||||
|
||||
export const notifyInvalidZoomedTimeRangeValueInURLQuery = () => ({
|
||||
export const notifyInvalidZoomedTimeRangeValueInURLQuery = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
icon: 'cube',
|
||||
message: `Invalid URL query value supplied for zoomed lower or zoomed upper time range.`,
|
||||
})
|
||||
|
||||
export const notifyViewerUnauthorizedToSetTempVars = () => ({
|
||||
export const notifyViewerUnauthorizedToSetTempVars = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Viewer role unauthorized to override template variable values from URL.`,
|
||||
})
|
||||
|
||||
// Rule Builder Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyAlertRuleCreated = ruleName => ({
|
||||
export const notifyAlertRuleCreated = (ruleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} created successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleCreateFailed = (ruleName, errorMessage) => ({
|
||||
export const notifyAlertRuleCreateFailed = (
|
||||
ruleName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was a problem creating ${ruleName}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleUpdated = ruleName => ({
|
||||
export const notifyAlertRuleUpdated = (ruleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} saved successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleUpdateFailed = (ruleName, errorMessage) => ({
|
||||
export const notifyAlertRuleUpdateFailed = (
|
||||
ruleName: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was a problem saving ${ruleName}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleDeleted = ruleName => ({
|
||||
export const notifyAlertRuleDeleted = (ruleName: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleDeleteFailed = ruleName => ({
|
||||
export const notifyAlertRuleDeleteFailed = (
|
||||
ruleName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `${ruleName} could not be deleted.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleStatusUpdated = (ruleName, updatedStatus) => ({
|
||||
export const notifyAlertRuleStatusUpdated = (
|
||||
ruleName: string,
|
||||
updatedStatus: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} ${updatedStatus} successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleStatusUpdateFailed = (ruleName, updatedStatus) => ({
|
||||
export const notifyAlertRuleStatusUpdateFailed = (
|
||||
ruleName: string,
|
||||
updatedStatus: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `${ruleName} could not be ${updatedStatus}.`,
|
||||
})
|
||||
|
||||
export const notifyAlertRuleRequiresQuery = () =>
|
||||
export const notifyAlertRuleRequiresQuery = (): string =>
|
||||
'Please select a Database, Measurement, and Field.'
|
||||
|
||||
export const notifyAlertRuleRequiresConditionValue = () =>
|
||||
export const notifyAlertRuleRequiresConditionValue = (): string =>
|
||||
'Please enter a value in the Conditions section.'
|
||||
|
||||
export const notifyAlertRuleDeadmanInvalid = () =>
|
||||
export const notifyAlertRuleDeadmanInvalid = (): string =>
|
||||
'Deadman rules require a Database and Measurement.'
|
||||
|
||||
// Kapacitor Configuration Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyKapacitorNameAlreadyTaken = kapacitorName => ({
|
||||
export const notifyKapacitorNameAlreadyTaken = (
|
||||
kapacitorName: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There is already a Kapacitor Connection named "${kapacitorName}".`,
|
||||
})
|
||||
|
||||
export const notifyCouldNotFindKapacitor = () => ({
|
||||
export const notifyCouldNotFindKapacitor = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not find a Kapacitor configuration for this source.',
|
||||
})
|
||||
|
||||
export const notifyRefreshKapacitorFailed = () => ({
|
||||
export const notifyRefreshKapacitorFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'There was an error getting the Kapacitor configuration.',
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointSaved = endpoint => ({
|
||||
export const notifyAlertEndpointSaved = (endpoint: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Alert configuration for ${endpoint} saved successfully.`,
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointSaveFailed = (endpoint, errorMessage) => ({
|
||||
export const notifyAlertEndpointSaveFailed = (
|
||||
endpoint: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was an error saving the alert configuration for ${endpoint}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointDeleteFailed = (
|
||||
endpoint,
|
||||
config,
|
||||
errorMessage
|
||||
) => ({
|
||||
endpoint: string,
|
||||
config: string,
|
||||
errorMessage: string
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was an error deleting the alert configuration for ${endpoint}/${config}: ${errorMessage}`,
|
||||
})
|
||||
|
||||
export const notifyAlertEndpointDeleted = (endpoint, config) => ({
|
||||
export const notifyAlertEndpointDeleted = (
|
||||
endpoint: string,
|
||||
config: string
|
||||
): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: `Alert configuration for ${endpoint}/${config} deleted successfully.`,
|
||||
})
|
||||
|
||||
export const notifyTestAlertSent = endpoint => ({
|
||||
export const notifyTestAlertSent = (endpoint: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
duration: TEN_SECONDS,
|
||||
message: `Test Alert sent to ${endpoint}. If the Alert does not reach its destination, please check your endpoint configuration settings.`,
|
||||
})
|
||||
|
||||
export const notifyTestAlertFailed = (endpoint, errorMessage?) => ({
|
||||
export const notifyTestAlertFailed = (
|
||||
endpoint: string,
|
||||
errorMessage: string = ''
|
||||
): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `There was an error sending a Test Alert to ${endpoint}${
|
||||
errorMessage ? `: ${errorMessage}` : '.'
|
||||
}`,
|
||||
message: `There was an error sending a Test Alert to ${endpoint} ${errorMessage}.`,
|
||||
})
|
||||
|
||||
export const notifyInvalidBatchSizeValue = () => ({
|
||||
export const notifyInvalidBatchSizeValue = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Batch Size cannot be empty.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorConnectionFailed = () => ({
|
||||
export const notifyKapacitorConnectionFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message:
|
||||
'Could not connect to Kapacitor. Check your connection settings in the Configuration page.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorCreated = () => ({
|
||||
export const notifyKapacitorCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message:
|
||||
'Connected to Kapacitor successfully! Configuring endpoints is optional.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorCreateFailed = () => ({
|
||||
export const notifyKapacitorCreateFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'There was a problem connecting to Kapacitor.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorUpdated = () => ({
|
||||
export const notifyKapacitorUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'Kapacitor Connection updated successfully.',
|
||||
})
|
||||
|
||||
export const notifyKapacitorUpdateFailed = () => ({
|
||||
export const notifyKapacitorUpdateFailed = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'There was a problem updating the Kapacitor Connection.',
|
||||
})
|
||||
|
||||
// TICKscript Notifications
|
||||
// ----------------------------------------------------------------------------
|
||||
export const notifyTickScriptCreated = () => ({
|
||||
export const notifyTickScriptCreated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'TICKscript successfully created.',
|
||||
})
|
||||
|
||||
export const notifyTickscriptCreationFailed = () =>
|
||||
export const notifyTickscriptCreationFailed = (): string =>
|
||||
'Failed to create TICKscript.'
|
||||
|
||||
export const notifyTickscriptUpdated = () => ({
|
||||
export const notifyTickscriptUpdated = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'TICKscript successfully updated.',
|
||||
})
|
||||
|
||||
export const notifyTickscriptUpdateFailed = () => 'Failed to update TICKscript.'
|
||||
export const notifyTickscriptUpdateFailed = (): string =>
|
||||
'Failed to update TICKscript.'
|
||||
|
||||
export const notifyTickscriptLoggingUnavailable = () => ({
|
||||
export const notifyTickscriptLoggingUnavailable = (): Notification => ({
|
||||
type: 'warning',
|
||||
icon: 'alert-triangle',
|
||||
duration: INFINITE,
|
||||
message: 'Kapacitor version 1.4 required to view TICKscript logs',
|
||||
})
|
||||
|
||||
export const notifyTickscriptLoggingError = () => ({
|
||||
export const notifyTickscriptLoggingError = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'Could not collect kapacitor logs',
|
||||
})
|
||||
|
||||
export const notifyKapacitorNotFound = () => ({
|
||||
export const notifyKapacitorNotFound = (): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not find a Kapacitor configuration for this source.',
|
||||
})
|
||||
|
||||
// Flux notifications
|
||||
export const validateSuccess = () => ({
|
||||
export const validateSuccess = (): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
message: 'No errors found. Happy Happy Joy Joy!',
|
||||
})
|
||||
|
||||
export const notifyCopyToClipboardSuccess = text => ({
|
||||
export const notifyCopyToClipboardSuccess = (text: string): Notification => ({
|
||||
...defaultSuccessNotification,
|
||||
icon: 'dash-h',
|
||||
message: `'${text}' has been copied to clipboard.`,
|
||||
})
|
||||
|
||||
export const notifyCopyToClipboardFailed = text => ({
|
||||
export const notifyCopyToClipboardFailed = (text: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `'${text}' was not copied to clipboard.`,
|
||||
})
|
||||
|
||||
// Service notifications
|
||||
export const couldNotGetServices = {
|
||||
export const couldNotGetServices: Notification = {
|
||||
...defaultErrorNotification,
|
||||
message: 'We could not get services',
|
||||
}
|
||||
|
||||
export const fluxCreated = {
|
||||
export const fluxCreated: Notification = {
|
||||
...defaultSuccessNotification,
|
||||
message: 'Flux Connection Created. Script your heart out!',
|
||||
}
|
||||
|
||||
export const fluxNotCreated = (message: string) => ({
|
||||
export const fluxNotCreated = (message: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message,
|
||||
})
|
||||
|
||||
export const fluxNotUpdated = (message: string) => ({
|
||||
export const fluxNotUpdated = (message: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message,
|
||||
})
|
||||
|
||||
export const fluxUpdated = {
|
||||
export const fluxUpdated: Notification = {
|
||||
...defaultSuccessNotification,
|
||||
message: 'Connection Updated. Rejoice!',
|
||||
}
|
||||
|
||||
export const fluxTimeSeriesError = (message: string) => ({
|
||||
export const fluxTimeSeriesError = (message: string): Notification => ({
|
||||
...defaultErrorNotification,
|
||||
message: `Could not get data: ${message}`,
|
||||
})
|
||||
|
||||
export const fluxResponseTruncatedError = () => {
|
||||
export const fluxResponseTruncatedError = (): Notification => {
|
||||
const BYTES_TO_MB = 1 / 1e6
|
||||
const APPROX_MAX_RESPONSE_MB = +(MAX_RESPONSE_BYTES * BYTES_TO_MB).toFixed(2)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ import {Source, NotificationFunc} from 'src/types'
|
|||
interface Props {
|
||||
source: Source
|
||||
sources: Source[]
|
||||
notify: NotificationFunc
|
||||
notify: (n: NotificationFunc) => void
|
||||
deleteKapacitor: actions.DeleteKapacitorAsync
|
||||
fetchKapacitors: actions.FetchKapacitorsAsync
|
||||
removeAndLoadSources: actions.RemoveAndLoadSources
|
||||
|
|
|
@ -0,0 +1,302 @@
|
|||
import React, {Component} from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import {withRouter} from 'react-router'
|
||||
import _ from 'lodash'
|
||||
import {getSource} from 'src/shared/apis'
|
||||
import {createSource, updateSource} from 'src/shared/apis'
|
||||
import {
|
||||
addSource as addSourceAction,
|
||||
updateSource as updateSourceAction,
|
||||
} from 'src/shared/actions/sources'
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
import {connect} from 'react-redux'
|
||||
import {bindActionCreators} from 'redux'
|
||||
|
||||
import Notifications from 'src/shared/components/Notifications'
|
||||
import SourceForm from 'src/sources/components/SourceForm'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
import {DEFAULT_SOURCE} from 'src/shared/constants'
|
||||
const initialPath = '/sources/new'
|
||||
|
||||
import {
|
||||
notifyErrorConnectingToSource,
|
||||
notifySourceCreationSucceeded,
|
||||
notifySourceCreationFailed,
|
||||
notifySourceUdpated,
|
||||
notifySourceUdpateFailed,
|
||||
} from 'src/shared/copy/notifications'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {Source} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
params: shape({
|
||||
id: string,
|
||||
sourceID: string,
|
||||
}),
|
||||
router: shape({
|
||||
push: func.isRequired,
|
||||
}).isRequired,
|
||||
location: shape({
|
||||
query: shape({
|
||||
redirectPath: string,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
notify: func.isRequired,
|
||||
addSource: func.isRequired,
|
||||
updateSource: func.isRequired,}
|
||||
|
||||
interface State {
|
||||
isLoading: boolean
|
||||
source: Source
|
||||
editMode: boolean
|
||||
isInitialSource: boolean}
|
||||
|
||||
@ErrorHandling
|
||||
class SourcePage extends Component<Props, State> {
|
||||
constructor(props:Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
source: DEFAULT_SOURCE,
|
||||
editMode: props.params.id !== undefined,
|
||||
isInitialSource: props.router.location.pathname === initialPath,
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const {editMode} = this.state
|
||||
const {params, notify} = this.props
|
||||
|
||||
if (!editMode) {
|
||||
return this.setState({isLoading: false})
|
||||
}
|
||||
|
||||
getSource(params.id)
|
||||
.then(({data: source}) => {
|
||||
this.setState({
|
||||
source: {...DEFAULT_SOURCE, ...source},
|
||||
isLoading: false,
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
notify(notifyErrorConnectingToSource(this._parseError(error)))
|
||||
this.setState({isLoading: false})
|
||||
})
|
||||
}
|
||||
|
||||
handleInputChange = e => {
|
||||
let val = e.target.value
|
||||
const name = e.target.name
|
||||
|
||||
if (e.target.type === 'checkbox') {
|
||||
val = e.target.checked
|
||||
}
|
||||
|
||||
this.setState(prevState => {
|
||||
const source = {
|
||||
...prevState.source,
|
||||
[name]: val,
|
||||
}
|
||||
|
||||
return {...prevState, source}
|
||||
})
|
||||
}
|
||||
|
||||
handleBlurSourceURL = () => {
|
||||
const {source, editMode} = this.state
|
||||
if (editMode) {
|
||||
this.setState(this._normalizeSource)
|
||||
return
|
||||
}
|
||||
|
||||
if (!source.url) {
|
||||
return
|
||||
}
|
||||
|
||||
this.setState(this._normalizeSource, this._createSourceOnBlur)
|
||||
}
|
||||
|
||||
handleSubmit = e => {
|
||||
e.preventDefault()
|
||||
const {isCreated, editMode} = this.state
|
||||
const isNewSource = !editMode
|
||||
|
||||
if (!isCreated && isNewSource) {
|
||||
return this.setState(this._normalizeSource, this._createSource)
|
||||
}
|
||||
|
||||
this.setState(this._normalizeSource, this._updateSource)
|
||||
}
|
||||
|
||||
gotoPurgatory = () => {
|
||||
const {router} = this.props
|
||||
router.push('/purgatory')
|
||||
}
|
||||
|
||||
_normalizeSource({source}) {
|
||||
const url = source.url.trim()
|
||||
if (source.url.startsWith('http')) {
|
||||
return {source: {...source, url}}
|
||||
}
|
||||
return {source: {...source, url: `http://${url}`}}
|
||||
}
|
||||
|
||||
_createSourceOnBlur = () => {
|
||||
const {source} = this.state
|
||||
// if there is a type on source it has already been created
|
||||
if (source.type) {
|
||||
return
|
||||
}
|
||||
createSource(source)
|
||||
.then(({data: sourceFromServer}) => {
|
||||
this.props.addSource(sourceFromServer)
|
||||
this.setState({
|
||||
source: {...DEFAULT_SOURCE, ...sourceFromServer},
|
||||
isCreated: true,
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
// dont want to flash this until they submit
|
||||
const error = this._parseError(err)
|
||||
console.error('Error creating InfluxDB connection: ', error)
|
||||
})
|
||||
}
|
||||
|
||||
_createSource = () => {
|
||||
const {source} = this.state
|
||||
const {notify} = this.props
|
||||
createSource(source)
|
||||
.then(({data: sourceFromServer}) => {
|
||||
this.props.addSource(sourceFromServer)
|
||||
this._redirect(sourceFromServer)
|
||||
notify(notifySourceCreationSucceeded(source.name))
|
||||
})
|
||||
.catch(error => {
|
||||
notify(notifySourceCreationFailed(source.name, this._parseError(error)))
|
||||
})
|
||||
}
|
||||
|
||||
_updateSource = () => {
|
||||
const {source} = this.state
|
||||
const {notify} = this.props
|
||||
updateSource(source)
|
||||
.then(({data: sourceFromServer}) => {
|
||||
this.props.updateSource(sourceFromServer)
|
||||
this._redirect(sourceFromServer)
|
||||
notify(notifySourceUdpated(source.name))
|
||||
})
|
||||
.catch(error => {
|
||||
notify(notifySourceUdpateFailed(source.name, this._parseError(error)))
|
||||
})
|
||||
}
|
||||
|
||||
_redirect = source => {
|
||||
const {isInitialSource} = this.state
|
||||
const {params, router} = this.props
|
||||
|
||||
if (isInitialSource) {
|
||||
return this._redirectToApp(source)
|
||||
}
|
||||
|
||||
router.push(`/sources/${params.sourceID}/manage-sources`)
|
||||
}
|
||||
|
||||
_redirectToApp = source => {
|
||||
const {location, router} = this.props
|
||||
const {redirectPath} = location.query
|
||||
|
||||
if (!redirectPath) {
|
||||
return router.push(`/sources/${source.id}/hosts`)
|
||||
}
|
||||
|
||||
const fixedPath = redirectPath.replace(
|
||||
/\/sources\/[^/]*/,
|
||||
`/sources/${source.id}`
|
||||
)
|
||||
return router.push(fixedPath)
|
||||
}
|
||||
|
||||
_parseError = error => {
|
||||
return _.get(error, ['data', 'message'], error)
|
||||
}
|
||||
|
||||
render() {
|
||||
const {isLoading, source, editMode, isInitialSource} = this.state
|
||||
|
||||
if (isLoading) {
|
||||
return <div className="page-spinner" />
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${isInitialSource ? '' : 'page'}`}>
|
||||
<Notifications />
|
||||
<div className="page-header">
|
||||
<div className="page-header__container page-header__source-page">
|
||||
<div className="page-header__col-md-8">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">
|
||||
{editMode
|
||||
? 'Configure InfluxDB Connection'
|
||||
: 'Add a New InfluxDB Connection'}
|
||||
</h1>
|
||||
</div>
|
||||
{isInitialSource ? null : (
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FancyScrollbar className="page-contents">
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-8 col-md-offset-2">
|
||||
<div className="panel">
|
||||
<SourceForm
|
||||
source={source}
|
||||
editMode={editMode}
|
||||
onInputChange={this.handleInputChange}
|
||||
onSubmit={this.handleSubmit}
|
||||
onBlurSourceURL={this.handleBlurSourceURL}
|
||||
isInitialSource={isInitialSource}
|
||||
gotoPurgatory={this.gotoPurgatory}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FancyScrollbar>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const {func, shape, string} = PropTypes
|
||||
|
||||
SourcePage.propTypes = {
|
||||
params: shape({
|
||||
id: string,
|
||||
sourceID: string,
|
||||
}),
|
||||
router: shape({
|
||||
push: func.isRequired,
|
||||
}).isRequired,
|
||||
location: shape({
|
||||
query: shape({
|
||||
redirectPath: string,
|
||||
}).isRequired,
|
||||
}).isRequired,
|
||||
notify: func.isRequired,
|
||||
addSource: func.isRequired,
|
||||
updateSource: func.isRequired,
|
||||
}
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
notify: bindActionCreators(notifyAction, dispatch),
|
||||
addSource: bindActionCreators(addSourceAction, dispatch),
|
||||
updateSource: bindActionCreators(updateSourceAction, dispatch),
|
||||
})
|
||||
export default connect(null, mapDispatchToProps)(withRouter(SourcePage))
|
|
@ -0,0 +1,76 @@
|
|||
// he is a library for safely encoding and decoding HTML Entities
|
||||
import he from 'he'
|
||||
|
||||
import {fetchJSONFeed as fetchJSONFeedAJAX} from 'src/status/apis'
|
||||
|
||||
import {notify} from 'src/shared/actions/notifications'
|
||||
import {notifyJSONFeedFailed} from 'src/shared/copy/notifications'
|
||||
|
||||
import {JSONFeedData} from 'src/types'
|
||||
|
||||
export enum ActionTypes {
|
||||
FETCH_JSON_FEED_REQUESTED = 'FETCH_JSON_FEED_REQUESTED',
|
||||
FETCH_JSON_FEED_COMPLETED = 'FETCH_JSON_FEED_COMPLETED',
|
||||
FETCH_JSON_FEED_FAILED = 'FETCH_JSON_FEED_FAILED',
|
||||
}
|
||||
|
||||
interface FetchJSONFeedRequestedAction {
|
||||
type: ActionTypes.FETCH_JSON_FEED_REQUESTED
|
||||
}
|
||||
|
||||
interface FetchJSONFeedCompletedAction {
|
||||
type: ActionTypes.FETCH_JSON_FEED_COMPLETED
|
||||
payload: {data: JSONFeedData}
|
||||
}
|
||||
|
||||
interface FetchJSONFeedFailedAction {
|
||||
type: ActionTypes.FETCH_JSON_FEED_FAILED
|
||||
}
|
||||
|
||||
export type Action =
|
||||
| FetchJSONFeedRequestedAction
|
||||
| FetchJSONFeedCompletedAction
|
||||
| FetchJSONFeedFailedAction
|
||||
|
||||
const fetchJSONFeedRequested = (): FetchJSONFeedRequestedAction => ({
|
||||
type: ActionTypes.FETCH_JSON_FEED_REQUESTED,
|
||||
})
|
||||
|
||||
const fetchJSONFeedCompleted = (
|
||||
data: JSONFeedData
|
||||
): FetchJSONFeedCompletedAction => ({
|
||||
type: ActionTypes.FETCH_JSON_FEED_COMPLETED,
|
||||
payload: {data},
|
||||
})
|
||||
|
||||
const fetchJSONFeedFailed = (): FetchJSONFeedFailedAction => ({
|
||||
type: ActionTypes.FETCH_JSON_FEED_FAILED,
|
||||
})
|
||||
|
||||
export const fetchJSONFeedAsync = (url: string) => async (
|
||||
dispatch
|
||||
): Promise<void> => {
|
||||
dispatch(fetchJSONFeedRequested())
|
||||
try {
|
||||
const {data} = await fetchJSONFeedAJAX(url)
|
||||
// data could be from a webpage, and thus would be HTML
|
||||
if (typeof data === 'string' || !data) {
|
||||
dispatch(fetchJSONFeedFailed())
|
||||
} else {
|
||||
// decode HTML entities from response text
|
||||
const decodedData = {
|
||||
...data,
|
||||
items: data.items.map(item => {
|
||||
item.title = he.decode(item.title)
|
||||
item.content_text = he.decode(item.content_text)
|
||||
return item
|
||||
}),
|
||||
}
|
||||
dispatch(fetchJSONFeedCompleted(decodedData))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
dispatch(fetchJSONFeedFailed())
|
||||
dispatch(notify(notifyJSONFeedFailed(url)))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
import React, {Component} from 'react'
|
||||
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
@ErrorHandling
|
||||
class GettingStarted extends Component {
|
||||
public render() {
|
||||
return (
|
||||
<FancyScrollbar className="getting-started--container">
|
||||
<div className="getting-started">
|
||||
<div className="getting-started--cell intro">
|
||||
<h5>
|
||||
<span className="icon cubo-uniform" /> Welcome to Chronograf!
|
||||
</h5>
|
||||
<p>Follow the links below to explore Chronograf’s features.</p>
|
||||
</div>
|
||||
<div className="getting-started--cell">
|
||||
<p>
|
||||
<strong>Install the TICK Stack</strong>
|
||||
<br />Save some time and use this handy tool to install the rest
|
||||
of the stack:
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://github.com/influxdata/sandbox" target="_blank">
|
||||
<span className="icon github" /> TICK Sandbox
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div className="getting-started--cell">
|
||||
<p>
|
||||
<strong>Guides</strong>
|
||||
</p>
|
||||
<p>
|
||||
<a
|
||||
href="https://docs.influxdata.com/chronograf/latest/guides/create-a-dashboard/"
|
||||
target="_blank"
|
||||
>
|
||||
Create a Dashboard
|
||||
</a>
|
||||
<br />
|
||||
<a
|
||||
href="https://docs.influxdata.com/chronograf/latest/guides/create-a-kapacitor-alert/"
|
||||
target="_blank"
|
||||
>
|
||||
Create a Kapacitor Alert
|
||||
</a>
|
||||
<br />
|
||||
<a
|
||||
href="https://docs.influxdata.com/chronograf/latest/guides/configure-kapacitor-event-handlers/"
|
||||
target="_blank"
|
||||
>
|
||||
Configure Kapacitor Event Handlers
|
||||
</a>
|
||||
<br />
|
||||
<a
|
||||
href="https://docs.influxdata.com/chronograf/latest/guides/transition-web-admin-interface/"
|
||||
target="_blank"
|
||||
>
|
||||
Transition from InfluxDB's Web Admin Interface
|
||||
</a>
|
||||
<br />
|
||||
<a
|
||||
href="https://docs.influxdata.com/chronograf/latest/guides/dashboard-template-variables/"
|
||||
target="_blank"
|
||||
>
|
||||
Dashboard Template Variables
|
||||
</a>
|
||||
<br />
|
||||
<a
|
||||
href="https://docs.influxdata.com/chronograf/latest/guides/advanced-kapacitor/"
|
||||
target="_blank"
|
||||
>
|
||||
Advanced Kapacitor Usage
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div className="getting-started--cell">
|
||||
<p>
|
||||
<strong>Questions & Comments</strong>
|
||||
</p>
|
||||
<p>
|
||||
If you have any product feedback please open a GitHub issue and
|
||||
we'll take a look. For any questions or other issues try posting
|
||||
on our
|
||||
<a href="https://community.influxdata.com/" target="_blank">
|
||||
Community Forum
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</FancyScrollbar>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default GettingStarted
|
|
@ -0,0 +1,45 @@
|
|||
import React, {SFC} from 'react'
|
||||
import {JSONFeedData} from 'src/types'
|
||||
|
||||
import moment from 'moment'
|
||||
|
||||
interface Props {
|
||||
data: JSONFeedData
|
||||
}
|
||||
|
||||
const JSONFeedReader: SFC<Props> = ({data}) =>
|
||||
data && data.items ? (
|
||||
<div className="newsfeed">
|
||||
{data.items
|
||||
? data.items.map(
|
||||
({
|
||||
id,
|
||||
date_published: datePublished,
|
||||
url,
|
||||
title,
|
||||
author: {name},
|
||||
image,
|
||||
content_text: contentText,
|
||||
}) => (
|
||||
<div key={id} className="newsfeed--post">
|
||||
<div className="newsfeed--date">
|
||||
{`${moment(datePublished).format('MMM DD')}`}
|
||||
</div>
|
||||
<div className="newsfeed--post-title">
|
||||
<a href={url} target="_blank">
|
||||
<h6>{title}</h6>
|
||||
</a>
|
||||
<span>by {name}</span>
|
||||
</div>
|
||||
<div className="newsfeed--content">
|
||||
{image ? <img src={image} /> : null}
|
||||
<p>{contentText}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
: null}
|
||||
</div>
|
||||
) : null
|
||||
|
||||
export default JSONFeedReader
|
|
@ -0,0 +1,83 @@
|
|||
import React, {Component} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import {fetchJSONFeedAsync} from 'src/status/actions'
|
||||
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import JSONFeedReader from 'src/status/components/JSONFeedReader'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
||||
import {JSONFeedData} from 'src/types'
|
||||
|
||||
interface Props {
|
||||
hasCompletedFetchOnce: boolean
|
||||
isFetching: boolean
|
||||
isFailed: boolean
|
||||
data: JSONFeedData
|
||||
fetchJSONFeed: (statusFeedURL: string) => void
|
||||
statusFeedURL: string
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class NewsFeed extends Component<Props> {
|
||||
public render() {
|
||||
const {hasCompletedFetchOnce, isFetching, isFailed, data} = this.props
|
||||
|
||||
if (!hasCompletedFetchOnce) {
|
||||
return isFailed ? (
|
||||
<div className="graph-empty">
|
||||
<p>Failed to load News Feed</p>
|
||||
</div>
|
||||
) : (
|
||||
// TODO: Factor this out of here and AutoRefresh
|
||||
<div className="graph-fetching">
|
||||
<div className="graph-spinner" />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<FancyScrollbar autoHide={false} className="newsfeed--container">
|
||||
{isFetching ? (
|
||||
// TODO: Factor this out of here and AutoRefresh
|
||||
<div className="graph-panel__refreshing">
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
) : null}
|
||||
{isFailed ? (
|
||||
<div className="graph-empty">
|
||||
<p>Failed to refresh News Feed</p>
|
||||
</div>
|
||||
) : null}
|
||||
<JSONFeedReader data={data} />
|
||||
</FancyScrollbar>
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: implement interval polling a la AutoRefresh
|
||||
public componentDidMount() {
|
||||
const {statusFeedURL, fetchJSONFeed} = this.props
|
||||
|
||||
fetchJSONFeed(statusFeedURL)
|
||||
}
|
||||
}
|
||||
const mstp = ({
|
||||
links: {
|
||||
external: {statusFeed: statusFeedURL},
|
||||
},
|
||||
JSONFeed: {hasCompletedFetchOnce, isFetching, isFailed, data},
|
||||
}) => ({
|
||||
hasCompletedFetchOnce,
|
||||
isFetching,
|
||||
isFailed,
|
||||
data,
|
||||
statusFeedURL,
|
||||
})
|
||||
|
||||
const mdtp = {
|
||||
fetchJSONFeed: fetchJSONFeedAsync,
|
||||
}
|
||||
|
||||
export default connect(mstp, mdtp)(NewsFeed)
|
|
@ -0,0 +1 @@
|
|||
export const RECENT_ALERTS_LIMIT = 30
|
|
@ -0,0 +1,108 @@
|
|||
import React, {Component} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
|
||||
import SourceIndicator from 'src/shared/components/SourceIndicator'
|
||||
import FancyScrollbar from 'src/shared/components/FancyScrollbar'
|
||||
import LayoutRenderer from 'src/shared/components/LayoutRenderer'
|
||||
|
||||
import {fixtureStatusPageCells} from 'src/status/fixtures'
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import {
|
||||
TEMP_VAR_DASHBOARD_TIME,
|
||||
TEMP_VAR_UPPER_DASHBOARD_TIME,
|
||||
} from 'src/shared/constants'
|
||||
import {Source, TimeRange, Cell} from 'src/types'
|
||||
|
||||
interface State {
|
||||
cells: Cell[]
|
||||
}
|
||||
|
||||
interface Props {
|
||||
source: Source
|
||||
autoRefresh: number
|
||||
timeRange: TimeRange
|
||||
}
|
||||
|
||||
@ErrorHandling
|
||||
class StatusPage extends Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
cells: fixtureStatusPageCells,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {source, autoRefresh, timeRange} = this.props
|
||||
const {cells} = this.state
|
||||
|
||||
const dashboardTime = {
|
||||
id: 'dashtime',
|
||||
tempVar: TEMP_VAR_DASHBOARD_TIME,
|
||||
type: 'constant',
|
||||
values: [
|
||||
{
|
||||
value: timeRange.lower,
|
||||
type: 'constant',
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const upperDashboardTime = {
|
||||
id: 'upperdashtime',
|
||||
tempVar: TEMP_VAR_UPPER_DASHBOARD_TIME,
|
||||
type: 'constant',
|
||||
values: [
|
||||
{
|
||||
value: 'now()',
|
||||
type: 'constant',
|
||||
selected: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const templates = [dashboardTime, upperDashboardTime]
|
||||
|
||||
return (
|
||||
<div className="page">
|
||||
<div className="page-header full-width">
|
||||
<div className="page-header__container">
|
||||
<div className="page-header__left">
|
||||
<h1 className="page-header__title">Status</h1>
|
||||
</div>
|
||||
<div className="page-header__right">
|
||||
<SourceIndicator />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FancyScrollbar className="page-contents">
|
||||
<div className="dashboard container-fluid full-width">
|
||||
{cells.length ? (
|
||||
<LayoutRenderer
|
||||
autoRefresh={autoRefresh}
|
||||
timeRange={timeRange}
|
||||
cells={cells}
|
||||
templates={templates}
|
||||
source={source}
|
||||
shouldNotBeEditable={true}
|
||||
isStatusPage={true}
|
||||
isEditable={false}
|
||||
/>
|
||||
) : (
|
||||
<span>Loading Status Page...</span>
|
||||
)}
|
||||
</div>
|
||||
</FancyScrollbar>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = ({statusUI: {autoRefresh, timeRange}}) => ({
|
||||
autoRefresh,
|
||||
timeRange,
|
||||
})
|
||||
|
||||
export default connect(mstp, null)(StatusPage)
|
|
@ -0,0 +1,51 @@
|
|||
import {JSONFeedData} from 'src/types'
|
||||
import {Action, ActionTypes} from 'src/status/actions'
|
||||
|
||||
export interface State {
|
||||
hasCompletedFetchOnce: boolean
|
||||
isFetching: boolean
|
||||
isFailed: boolean
|
||||
data: JSONFeedData
|
||||
}
|
||||
|
||||
const initialState: State = {
|
||||
hasCompletedFetchOnce: false,
|
||||
isFetching: false,
|
||||
isFailed: false,
|
||||
data: null,
|
||||
}
|
||||
|
||||
const JSONFeedReducer = (state: State = initialState, action: Action) => {
|
||||
switch (action.type) {
|
||||
case ActionTypes.FETCH_JSON_FEED_REQUESTED: {
|
||||
return {...state, isFetching: true, isFailed: false}
|
||||
}
|
||||
|
||||
case ActionTypes.FETCH_JSON_FEED_COMPLETED: {
|
||||
const {data} = action.payload
|
||||
|
||||
return {
|
||||
...state,
|
||||
hasCompletedFetchOnce: true,
|
||||
isFetching: false,
|
||||
isFailed: false,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
case ActionTypes.FETCH_JSON_FEED_FAILED: {
|
||||
return {
|
||||
...state,
|
||||
isFetching: false,
|
||||
isFailed: true,
|
||||
data: null,
|
||||
}
|
||||
}
|
||||
|
||||
default: {
|
||||
return state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default JSONFeedReducer
|
|
@ -0,0 +1,4 @@
|
|||
import JSONFeed from 'src/status/reducers/JSONFeed'
|
||||
export default {
|
||||
JSONFeed,
|
||||
}
|
|
@ -6,6 +6,6 @@ export interface Notification {
|
|||
message: string
|
||||
}
|
||||
|
||||
export type NotificationFunc = (message: any) => Notification
|
||||
export type NotificationFunc = (message: string) => Notification
|
||||
|
||||
export type NotificationAction = (message: Notification) => void
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
interface JSONFeedDataItem {
|
||||
id: string
|
||||
url: string
|
||||
title: string
|
||||
content_text: string
|
||||
date_published: string
|
||||
date_modified: string
|
||||
image: string
|
||||
author: {
|
||||
name: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface JSONFeedData {
|
||||
version: string
|
||||
user_comment: string
|
||||
home_page_url: string
|
||||
feed_url: string
|
||||
title: string
|
||||
description: string
|
||||
items: JSONFeedDataItem[]
|
||||
}
|
|
@ -30,7 +30,7 @@ describe('Normalizers.DashboardTime', () => {
|
|||
})
|
||||
|
||||
it('can remove timeRanges with incorrect dashboardID', () => {
|
||||
const ranges = [{dashboardID: '1', upper, lower}, timeRange]
|
||||
const ranges = [{dashboardID: 1, upper, lower}, timeRange]
|
||||
|
||||
const actual = normalizer(ranges)
|
||||
const expected = [timeRange]
|
||||
|
|
Loading…
Reference in New Issue