Merge pull request #1764 from influxdata/feat/onboarding-routing
Handling onboarding with react routerpull/10616/head
commit
3b8578c7d6
|
@ -1,6 +1,7 @@
|
|||
// Libraries
|
||||
import React, {ReactElement, PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {InjectedRouter} from 'react-router'
|
||||
|
||||
// APIs
|
||||
import {getSetupStatus} from 'src/onboarding/apis'
|
||||
|
@ -10,8 +11,9 @@ import {notify as notifyAction} from 'src/shared/actions/notifications'
|
|||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import OnboardingWizard from 'src/onboarding/containers/OnboardingWizard'
|
||||
import Notifications from 'src/shared/components/notifications/Notifications'
|
||||
|
||||
// Utils
|
||||
import {isOnboardingURL} from 'src/onboarding/utils'
|
||||
|
||||
// Types
|
||||
import {Notification, NotificationFunc, RemoteDataState} from 'src/types'
|
||||
|
@ -24,6 +26,7 @@ interface State {
|
|||
|
||||
interface Props {
|
||||
links: Links
|
||||
router: InjectedRouter
|
||||
children: ReactElement<any>
|
||||
notify: (message: Notification | NotificationFunc) => void
|
||||
}
|
||||
|
@ -40,35 +43,35 @@ export class Setup extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
public async componentDidMount() {
|
||||
const {links} = this.props
|
||||
const {links, router} = this.props
|
||||
|
||||
if (isOnboardingURL()) {
|
||||
this.setState({
|
||||
loading: RemoteDataState.Done,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const isSetupAllowed = await getSetupStatus(links.setup)
|
||||
this.setState({
|
||||
loading: RemoteDataState.Done,
|
||||
isSetupComplete: !isSetupAllowed,
|
||||
})
|
||||
|
||||
if (!isSetupAllowed) {
|
||||
return
|
||||
}
|
||||
|
||||
router.push('/onboarding/0')
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {isSetupComplete} = this.state
|
||||
if (this.isLoading) {
|
||||
return <div className="page-spinner" />
|
||||
}
|
||||
if (!isSetupComplete) {
|
||||
return (
|
||||
<div className="chronograf-root">
|
||||
<Notifications inPresentationMode={true} />
|
||||
<OnboardingWizard onCompleteSetup={this.handleCompleteSetup} />
|
||||
</div>
|
||||
)
|
||||
} else {
|
||||
return this.props.children && React.cloneElement(this.props.children)
|
||||
}
|
||||
}
|
||||
|
||||
public handleCompleteSetup = () => {
|
||||
this.setState({isSetupComplete: true})
|
||||
}
|
||||
|
||||
private get isLoading(): boolean {
|
||||
const {loading} = this.state
|
||||
return (
|
||||
|
|
|
@ -33,6 +33,8 @@ import GetLinks from 'src/shared/containers/GetLinks'
|
|||
import GetMe from 'src/shared/containers/GetMe'
|
||||
import SourcesPage from 'src/sources/components/SourcesPage'
|
||||
|
||||
import OnboardingWizardPage from 'src/onboarding/containers/OnboardingWizardPage'
|
||||
|
||||
// Actions
|
||||
import {disablePresentationMode} from 'src/shared/actions/app'
|
||||
|
||||
|
@ -77,6 +79,14 @@ class Root extends PureComponent {
|
|||
<Router history={history}>
|
||||
<Route component={GetLinks}>
|
||||
<Route component={Setup}>
|
||||
<Route
|
||||
path="/onboarding/:stepID"
|
||||
component={OnboardingWizardPage}
|
||||
/>
|
||||
<Route
|
||||
path="/onboarding/:stepID/:substepID"
|
||||
component={OnboardingWizardPage}
|
||||
/>
|
||||
<Route component={Signin}>
|
||||
<Route component={GetMe}>
|
||||
<Route component={GetOrganizations}>
|
||||
|
@ -116,8 +126,8 @@ class Root extends PureComponent {
|
|||
</Route>
|
||||
</Route>
|
||||
</Route>
|
||||
<Route path="*" component={NotFound} />
|
||||
</Route>
|
||||
<Route path="*" component={NotFound} />
|
||||
</Router>
|
||||
</Provider>
|
||||
)
|
||||
|
|
|
@ -4,12 +4,7 @@ import {StepStatus} from 'src/clockface/constants/wizard'
|
|||
// Types
|
||||
import {SetupParams} from 'src/onboarding/apis'
|
||||
|
||||
export type Action =
|
||||
| SetSetupParams
|
||||
| IncrementCurrentStepIndex
|
||||
| DecrementCurrentStepIndex
|
||||
| SetCurrentStepIndex
|
||||
| SetStepStatus
|
||||
export type Action = SetSetupParams | SetStepStatus
|
||||
|
||||
interface SetSetupParams {
|
||||
type: 'SET_SETUP_PARAMS'
|
||||
|
@ -21,32 +16,6 @@ export const setSetupParams = (setupParams: SetupParams): SetSetupParams => ({
|
|||
payload: {setupParams},
|
||||
})
|
||||
|
||||
interface SetCurrentStepIndex {
|
||||
type: 'SET_CURRENT_STEP_INDEX'
|
||||
payload: {index: number}
|
||||
}
|
||||
|
||||
export const setCurrentStepIndex = (index: number): SetCurrentStepIndex => ({
|
||||
type: 'SET_CURRENT_STEP_INDEX',
|
||||
payload: {index},
|
||||
})
|
||||
|
||||
interface IncrementCurrentStepIndex {
|
||||
type: 'INCREMENT_CURRENT_STEP_INDEX'
|
||||
}
|
||||
|
||||
export const incrementCurrentStepIndex = (): IncrementCurrentStepIndex => ({
|
||||
type: 'INCREMENT_CURRENT_STEP_INDEX',
|
||||
})
|
||||
|
||||
interface DecrementCurrentStepIndex {
|
||||
type: 'DECREMENT_CURRENT_STEP_INDEX'
|
||||
}
|
||||
|
||||
export const decrementCurrentStepIndex = (): DecrementCurrentStepIndex => ({
|
||||
type: 'DECREMENT_CURRENT_STEP_INDEX',
|
||||
})
|
||||
|
||||
interface SetStepStatus {
|
||||
type: 'SET_STEP_STATUS'
|
||||
payload: {index: number; status: StepStatus}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import _ from 'lodash'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -16,27 +17,44 @@ import ConfigureDataSourceSwitcher from 'src/onboarding/components/configureStep
|
|||
import {OnboardingStepProps} from 'src/onboarding/containers/OnboardingWizard'
|
||||
import {TelegrafPlugin, DataLoaderType} from 'src/types/v2/dataLoaders'
|
||||
|
||||
export interface Props extends OnboardingStepProps {
|
||||
export interface OwnProps extends OnboardingStepProps {
|
||||
telegrafPlugins: TelegrafPlugin[]
|
||||
type: DataLoaderType
|
||||
}
|
||||
|
||||
interface State {
|
||||
currentDataSourceIndex: number
|
||||
interface RouterProps {
|
||||
params: {
|
||||
stepID: string
|
||||
substepID: string
|
||||
}
|
||||
}
|
||||
|
||||
type Props = OwnProps & WithRouterProps & RouterProps
|
||||
|
||||
@ErrorHandling
|
||||
class ConfigureDataSourceStep extends PureComponent<Props, State> {
|
||||
class ConfigureDataSourceStep extends PureComponent<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
this.state = {
|
||||
currentDataSourceIndex: 0,
|
||||
public componentDidMount() {
|
||||
const {
|
||||
router,
|
||||
params: {stepID, substepID},
|
||||
} = this.props
|
||||
|
||||
if (substepID === undefined) {
|
||||
router.replace(`/onboarding/${stepID}/0`)
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {telegrafPlugins, type, setupParams} = this.props
|
||||
const {
|
||||
telegrafPlugins,
|
||||
type,
|
||||
params: {substepID},
|
||||
setupParams,
|
||||
} = this.props
|
||||
|
||||
return (
|
||||
<div className="onboarding-step">
|
||||
|
@ -44,8 +62,8 @@ class ConfigureDataSourceStep extends PureComponent<Props, State> {
|
|||
bucket={_.get(setupParams, 'bucket', '')}
|
||||
org={_.get(setupParams, 'org', '')}
|
||||
telegrafPlugins={telegrafPlugins}
|
||||
currentIndex={this.state.currentDataSourceIndex}
|
||||
dataLoaderType={type}
|
||||
currentIndex={+substepID}
|
||||
/>
|
||||
<div className="wizard-button-bar">
|
||||
<Button
|
||||
|
@ -68,26 +86,27 @@ class ConfigureDataSourceStep extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleNext = () => {
|
||||
const {onIncrementCurrentStepIndex, telegrafPlugins} = this.props
|
||||
const {currentDataSourceIndex} = this.state
|
||||
const {
|
||||
onIncrementCurrentStepIndex,
|
||||
telegrafPlugins,
|
||||
params: {substepID, stepID},
|
||||
router,
|
||||
} = this.props
|
||||
|
||||
if (currentDataSourceIndex >= telegrafPlugins.length - 1) {
|
||||
const index = +substepID
|
||||
|
||||
if (index >= telegrafPlugins.length - 1) {
|
||||
onIncrementCurrentStepIndex()
|
||||
} else {
|
||||
this.setState({currentDataSourceIndex: currentDataSourceIndex + 1})
|
||||
router.push(`/onboarding/${stepID}/${index + 1}`)
|
||||
}
|
||||
}
|
||||
|
||||
private handlePrevious = () => {
|
||||
const {onDecrementCurrentStepIndex} = this.props
|
||||
const {currentDataSourceIndex} = this.state
|
||||
const {router} = this.props
|
||||
|
||||
if (currentDataSourceIndex === 0) {
|
||||
onDecrementCurrentStepIndex()
|
||||
} else {
|
||||
this.setState({currentDataSourceIndex: currentDataSourceIndex - 1})
|
||||
}
|
||||
router.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
export default ConfigureDataSourceStep
|
||||
export default withRouter<OwnProps>(ConfigureDataSourceStep)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Libraries
|
||||
import React, {PureComponent} from 'react'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
|
@ -21,7 +22,7 @@ import {
|
|||
TelegrafPluginName,
|
||||
} from 'src/types/v2/dataLoaders'
|
||||
|
||||
export interface Props extends OnboardingStepProps {
|
||||
export interface OwnProps extends OnboardingStepProps {
|
||||
bucket: string
|
||||
telegrafPlugins: TelegrafPlugin[]
|
||||
type: DataLoaderType
|
||||
|
@ -30,6 +31,15 @@ export interface Props extends OnboardingStepProps {
|
|||
onSetDataLoadersType: (type: DataLoaderType) => void
|
||||
}
|
||||
|
||||
interface RouterProps {
|
||||
params: {
|
||||
stepID: string
|
||||
substepID: string
|
||||
}
|
||||
}
|
||||
|
||||
type Props = OwnProps & RouterProps & WithRouterProps
|
||||
|
||||
interface State {
|
||||
showStreamingSources: boolean
|
||||
}
|
||||
|
@ -72,7 +82,7 @@ class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
|
||||
private get title(): string {
|
||||
const {bucket} = this.props
|
||||
if (this.state.showStreamingSources) {
|
||||
if (this.isStreaming) {
|
||||
return `Select Streaming Data Sources to add to ${bucket ||
|
||||
'your bucket'}`
|
||||
}
|
||||
|
@ -80,10 +90,7 @@ class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private get selector(): JSX.Element {
|
||||
if (
|
||||
this.props.type === DataLoaderType.Streaming &&
|
||||
this.state.showStreamingSources
|
||||
) {
|
||||
if (this.props.type === DataLoaderType.Streaming && this.isStreaming) {
|
||||
return (
|
||||
<StreamingDataSourceSelector
|
||||
telegrafPlugins={this.props.telegrafPlugins}
|
||||
|
@ -100,11 +107,13 @@ class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleClickNext = () => {
|
||||
if (
|
||||
this.props.type === DataLoaderType.Streaming &&
|
||||
!this.state.showStreamingSources
|
||||
) {
|
||||
this.setState({showStreamingSources: true})
|
||||
const {
|
||||
router,
|
||||
params: {stepID},
|
||||
} = this.props
|
||||
|
||||
if (this.props.type === DataLoaderType.Streaming && !this.isStreaming) {
|
||||
router.push(`/onboarding/${stepID}/streaming`)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -112,11 +121,6 @@ class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
}
|
||||
|
||||
private handleClickBack = () => {
|
||||
if (this.props.type === DataLoaderType.Streaming) {
|
||||
this.setState({showStreamingSources: false})
|
||||
return
|
||||
}
|
||||
|
||||
this.props.onDecrementCurrentStepIndex()
|
||||
}
|
||||
|
||||
|
@ -145,6 +149,10 @@ class SelectDataSourceStep extends PureComponent<Props, State> {
|
|||
}
|
||||
this.props.onAddTelegrafPlugin(plugin)
|
||||
}
|
||||
|
||||
private get isStreaming(): boolean {
|
||||
return this.props.params.substepID === 'streaming'
|
||||
}
|
||||
}
|
||||
|
||||
export default SelectDataSourceStep
|
||||
export default withRouter<OwnProps>(SelectDataSourceStep)
|
||||
|
|
|
@ -16,13 +16,8 @@ import OnboardingStepSwitcher from 'src/onboarding/components/OnboardingStepSwit
|
|||
|
||||
// Actions
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
import {
|
||||
setSetupParams,
|
||||
incrementCurrentStepIndex,
|
||||
decrementCurrentStepIndex,
|
||||
setCurrentStepIndex,
|
||||
setStepStatus,
|
||||
} from 'src/onboarding/actions/steps'
|
||||
import {setSetupParams, setStepStatus} from 'src/onboarding/actions/steps'
|
||||
|
||||
import {
|
||||
setDataLoadersType,
|
||||
addTelegrafPlugin,
|
||||
|
@ -62,14 +57,15 @@ interface OwnProps {
|
|||
startStep?: number
|
||||
stepStatuses?: StepStatus[]
|
||||
onCompleteSetup: () => void
|
||||
currentStepIndex: number
|
||||
onIncrementCurrentStepIndex: () => void
|
||||
onDecrementCurrentStepIndex: () => void
|
||||
onSetCurrentStepIndex: (stepNumber: number) => void
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
notify: (message: Notification | NotificationFunc) => void
|
||||
onSetSetupParams: typeof setSetupParams
|
||||
onIncrementCurrentStepIndex: typeof incrementCurrentStepIndex
|
||||
onDecrementCurrentStepIndex: typeof decrementCurrentStepIndex
|
||||
onSetCurrentStepIndex: typeof setCurrentStepIndex
|
||||
onSetStepStatus: typeof setStepStatus
|
||||
onSetDataLoadersType: typeof setDataLoadersType
|
||||
onAddTelegrafPlugin: typeof addTelegrafPlugin
|
||||
|
@ -84,7 +80,6 @@ interface DataLoadersProps {
|
|||
|
||||
interface StateProps {
|
||||
links: Links
|
||||
currentStepIndex: number
|
||||
stepStatuses: StepStatus[]
|
||||
setupParams: SetupParams
|
||||
dataLoaders: DataLoadersProps
|
||||
|
@ -238,12 +233,11 @@ class OnboardingWizard extends PureComponent<Props> {
|
|||
const mstp = ({
|
||||
links,
|
||||
onboarding: {
|
||||
steps: {currentStepIndex, stepStatuses, setupParams},
|
||||
steps: {stepStatuses, setupParams},
|
||||
dataLoaders,
|
||||
},
|
||||
}: AppState): StateProps => ({
|
||||
links,
|
||||
currentStepIndex,
|
||||
stepStatuses,
|
||||
setupParams,
|
||||
dataLoaders,
|
||||
|
@ -252,9 +246,6 @@ const mstp = ({
|
|||
const mdtp: DispatchProps = {
|
||||
notify: notifyAction,
|
||||
onSetSetupParams: setSetupParams,
|
||||
onDecrementCurrentStepIndex: decrementCurrentStepIndex,
|
||||
onIncrementCurrentStepIndex: incrementCurrentStepIndex,
|
||||
onSetCurrentStepIndex: setCurrentStepIndex,
|
||||
onSetStepStatus: setStepStatus,
|
||||
onSetDataLoadersType: setDataLoadersType,
|
||||
onAddTelegrafPlugin: addTelegrafPlugin,
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
// Libraries
|
||||
import React, {ReactElement, PureComponent} from 'react'
|
||||
import {connect} from 'react-redux'
|
||||
import {withRouter, WithRouterProps} from 'react-router'
|
||||
|
||||
// Actions
|
||||
import {notify as notifyAction} from 'src/shared/actions/notifications'
|
||||
|
||||
// Components
|
||||
import {ErrorHandling} from 'src/shared/decorators/errors'
|
||||
import OnboardingWizard from 'src/onboarding/containers/OnboardingWizard'
|
||||
import Notifications from 'src/shared/components/notifications/Notifications'
|
||||
|
||||
// Types
|
||||
import {Notification, NotificationFunc, RemoteDataState} from 'src/types'
|
||||
import {Links} from 'src/types/v2/links'
|
||||
|
||||
interface State {
|
||||
loading: RemoteDataState
|
||||
isSetupComplete: boolean
|
||||
}
|
||||
|
||||
interface PassedProps {
|
||||
children: ReactElement<any>
|
||||
params: {
|
||||
stepID: string
|
||||
}
|
||||
}
|
||||
|
||||
interface ConnectedStateProps {
|
||||
links: Links
|
||||
}
|
||||
|
||||
interface ConnectedDispatchProps {
|
||||
notify: (message: Notification | NotificationFunc) => void
|
||||
}
|
||||
|
||||
type Props = PassedProps &
|
||||
WithRouterProps &
|
||||
ConnectedStateProps &
|
||||
ConnectedDispatchProps
|
||||
|
||||
@ErrorHandling
|
||||
export class OnboardingWizardPage extends PureComponent<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
loading: RemoteDataState.NotStarted,
|
||||
isSetupComplete: false,
|
||||
}
|
||||
}
|
||||
|
||||
public render() {
|
||||
const {params} = this.props
|
||||
|
||||
return (
|
||||
<div className="chronograf-root">
|
||||
<Notifications inPresentationMode={true} />
|
||||
<OnboardingWizard
|
||||
onDecrementCurrentStepIndex={this.handleDecrementStepIndex}
|
||||
onIncrementCurrentStepIndex={this.handleIncrementStepIndex}
|
||||
onSetCurrentStepIndex={this.setStepIndex}
|
||||
currentStepIndex={+params.stepID}
|
||||
onCompleteSetup={this.handleCompleteSetup}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
public handleCompleteSetup = () => {
|
||||
this.setState({isSetupComplete: true})
|
||||
}
|
||||
|
||||
private handleDecrementStepIndex = () => {
|
||||
const {router} = this.props
|
||||
|
||||
router.goBack()
|
||||
}
|
||||
|
||||
private handleIncrementStepIndex = () => {
|
||||
const {
|
||||
params: {stepID},
|
||||
} = this.props
|
||||
|
||||
this.setStepIndex(+stepID + 1)
|
||||
}
|
||||
|
||||
private setStepIndex = (index: number) => {
|
||||
const {router} = this.props
|
||||
|
||||
router.push(`/onboarding/${index}`)
|
||||
}
|
||||
}
|
||||
|
||||
const mstp = ({links}) => ({links})
|
||||
|
||||
const mdtp = {
|
||||
notify: notifyAction,
|
||||
}
|
||||
|
||||
export default connect<
|
||||
ConnectedStateProps,
|
||||
ConnectedDispatchProps,
|
||||
PassedProps
|
||||
>(
|
||||
mstp,
|
||||
mdtp
|
||||
)(withRouter<Props>(OnboardingWizardPage))
|
|
@ -6,13 +6,11 @@ import {Action} from 'src/onboarding/actions/steps'
|
|||
import {SetupParams} from 'src/onboarding/apis'
|
||||
|
||||
export interface OnboardingStepsState {
|
||||
currentStepIndex: number
|
||||
stepStatuses: StepStatus[]
|
||||
setupParams: SetupParams
|
||||
}
|
||||
|
||||
const INITIAL_STATE: OnboardingStepsState = {
|
||||
currentStepIndex: 0,
|
||||
stepStatuses: new Array(6).fill(StepStatus.Incomplete),
|
||||
setupParams: null,
|
||||
}
|
||||
|
@ -24,12 +22,6 @@ export default (
|
|||
switch (action.type) {
|
||||
case 'SET_SETUP_PARAMS':
|
||||
return {...state, setupParams: action.payload.setupParams}
|
||||
case 'INCREMENT_CURRENT_STEP_INDEX':
|
||||
return {...state, currentStepIndex: state.currentStepIndex + 1}
|
||||
case 'DECREMENT_CURRENT_STEP_INDEX':
|
||||
return {...state, currentStepIndex: state.currentStepIndex - 1}
|
||||
case 'SET_CURRENT_STEP_INDEX':
|
||||
return {...state, currentStepIndex: action.payload.index}
|
||||
case 'SET_STEP_STATUS':
|
||||
const stepStatuses = [...state.stepStatuses]
|
||||
stepStatuses[action.payload.index] = action.payload.status
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const isOnboardingURL = () => {
|
||||
return !!window.location.pathname.match(/\/onboarding/)
|
||||
}
|
Loading…
Reference in New Issue