Actually type notifications

pull/10616/head
ebb-tide 2018-06-18 13:45:11 -07:00
parent a14fdc806d
commit 6ff87be8e0
17 changed files with 1043 additions and 168 deletions

View File

@ -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

View File

@ -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,

View File

@ -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))
}
}

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -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)))
}
}

View File

@ -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 Chronografs 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&nbsp;
<a href="https://community.influxdata.com/" target="_blank">
Community Forum
</a>.
</p>
</div>
</div>
</FancyScrollbar>
)
}
}
export default GettingStarted

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1 @@
export const RECENT_ALERTS_LIMIT = 30

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,4 @@
import JSONFeed from 'src/status/reducers/JSONFeed'
export default {
JSONFeed,
}

View File

@ -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

22
ui/src/types/status.ts Normal file
View File

@ -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[]
}

View File

@ -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]