1717import React from "react"
1818import { v4 } from "uuid"
1919import { i18n , Tab } from "@kui-shell/core"
20- import { Markdown , Card , CardResponse , Icons } from "@kui-shell/plugin-client-common"
21- import { Chip , ChipGroup , Grid , GridItem , Progress , Tile , WizardStep } from "@patternfly/react-core"
20+ import { Card , CardResponse , Icons , Loading , Markdown } from "@kui-shell/plugin-client-common"
21+ import { ButtonProps , Chip , ChipGroup , Grid , GridItem , Progress , Tile , WizardStep } from "@patternfly/react-core"
2222
2323import {
2424 Choice ,
@@ -44,7 +44,7 @@ import {
4444} from "madwizard"
4545
4646import read from "../read"
47- import Wizard , { Props as WizardProps } from "./Wizard/KWizard"
47+ import Wizard from "./Wizard/KWizard"
4848import { statusToClassName , statusToIcon } from "./StatusUI"
4949
5050import "@kui-shell/plugin-client-common/web/scss/components/Wizard/Guide.scss"
@@ -69,7 +69,7 @@ export type Props = Choices &
6969
7070type State = Choices & {
7171 /** Internal error in rendering? */
72- error ?: Error
72+ error ?: unknown
7373
7474 /** Graph of code blocks to be executed */
7575 graph : OrderedGraph
@@ -96,28 +96,20 @@ export default class Guide extends React.PureComponent<Props, State> {
9696
9797 public constructor ( props : Props ) {
9898 super ( props )
99- this . state = {
100- startAtStep : 0 ,
101- isRunning : false ,
102- graph : undefined ,
103- frontier : undefined ,
104- wizard : undefined ,
105- wizardStepStatus : undefined ,
106- choices : props . choices ,
107- }
10899 setTimeout ( ( ) => this . init ( props ) )
109100 }
110101
111102 /**
112103 * TODO move to a more common location?
113104 */
114105 private static isValidFrontier ( frontier : ReturnType < typeof findChoiceFrontier > ) : boolean {
115- return frontier . length > 0 && frontier . every ( ( _ ) => _ . prereqs . length > 0 || ! ! _ . choice )
106+ return frontier . length > 0 && frontier . every ( ( _ ) => ( _ . prereqs && _ . prereqs . length > 0 ) || ! ! _ . choice )
116107 }
117108
118109 private async init ( props : Props , useTheseChoices ?: State [ "choices" ] ) {
119110 const choices = useTheseChoices || props . choices
120111 const newGraph = await compile ( props . blocks , choices , undefined , "sequence" , props . title , props . description )
112+ choices . onChoice ( this . onChoiceFromAbove )
121113
122114 this . setState ( ( state ) => {
123115 const noChangeToGraph = state && sameGraph ( state . graph , newGraph )
@@ -126,7 +118,7 @@ export default class Guide extends React.PureComponent<Props, State> {
126118 const frontier = noChangeToGraph && state && state . frontier ? state . frontier : findChoiceFrontier ( graph )
127119
128120 const startAtStep = state ? state . startAtStep : 1
129- const wizard = wizardify ( graph , { previous : state . wizard } )
121+ const wizard = wizardify ( graph , { previous : state ? state . wizard : undefined } )
130122 const wizardStepStatus = noChangeToGraph && state ? state . wizardStepStatus : [ ]
131123
132124 const isRunning = state ? state . isRunning : false
@@ -135,12 +127,10 @@ export default class Guide extends React.PureComponent<Props, State> {
135127 } )
136128 }
137129
138- public componentDidMount ( ) {
139- this . state . choices . onChoice ( this . onChoiceFromAbove )
140- }
141-
142130 public componentWillUnmount ( ) {
143- this . state . choices . offChoice ( this . onChoiceFromAbove )
131+ if ( this . state ) {
132+ this . state . choices . offChoice ( this . onChoiceFromAbove )
133+ }
144134 }
145135
146136 /** @return a wrapper UI for the content of a wizard step */
@@ -185,7 +175,9 @@ export default class Guide extends React.PureComponent<Props, State> {
185175 private readonly onChoice = ( evt : React . MouseEvent ) => {
186176 const group = evt . currentTarget . getAttribute ( "data-choice-group" )
187177 const title = evt . currentTarget . getAttribute ( "data-choice-title" )
188- this . props . choices . set ( group , title )
178+ if ( group && title ) {
179+ this . props . choices . set ( group , title )
180+ }
189181 }
190182
191183 /** @return UI that offers the user a choice */
@@ -246,11 +238,13 @@ export default class Guide extends React.PureComponent<Props, State> {
246238 step : Object . assign ( { } , step , {
247239 name : graph . title ,
248240 component : this . tilesForChoice ( graph ) ,
249- stepNavItemProps : isFirstChoice && {
250- children : this . wizardStepDescription (
251- < span className = "sub-text" > { this . choiceIcon1 } This step requires you to choose how to proceed</ span >
252- ) ,
253- } ,
241+ stepNavItemProps : isFirstChoice
242+ ? {
243+ children : this . wizardStepDescription (
244+ < span className = "sub-text" > { this . choiceIcon1 } This step requires you to choose how to proceed</ span >
245+ ) ,
246+ }
247+ : undefined ,
254248 } ) ,
255249 }
256250 }
@@ -273,22 +267,20 @@ export default class Guide extends React.PureComponent<Props, State> {
273267 /** @return the `WizardStep` models for this Guide */
274268 private wizardSteps ( ) {
275269 let isFirstChoice = true
276- return this . state . wizard
277- . reduce ( ( uiSteps , _ , idx , A ) => {
278- if ( isChoiceStep ( _ ) ) {
279- const ui = this . choiceUI ( _ , isFirstChoice )
280- isFirstChoice = false
281- uiSteps . push ( ui )
282- } else if ( isTaskStep ( _ ) ) {
283- const previous = A [ idx - 1 ]
284- if ( ! previous || ! isTaskStep ( previous ) || previous . step . name !== _ . step . name ) {
285- // task steps with multiple code blocks... combine them into one ui step
286- uiSteps . push ( this . taskUI ( _ ) )
287- }
270+ return this . state . wizard . reduce ( ( uiSteps , _ , idx , A ) => {
271+ if ( isChoiceStep ( _ ) ) {
272+ const ui = this . choiceUI ( _ , isFirstChoice )
273+ isFirstChoice = false
274+ uiSteps . push ( ui )
275+ } else if ( isTaskStep ( _ ) ) {
276+ const previous = A [ idx - 1 ]
277+ if ( ! previous || ! isTaskStep ( previous ) || previous . step . name !== _ . step . name ) {
278+ // task steps with multiple code blocks... combine them into one ui step
279+ uiSteps . push ( this . taskUI ( _ ) )
288280 }
289- return uiSteps
290- } , [ ] )
291- . filter ( Boolean )
281+ }
282+ return uiSteps
283+ } , [ ] as ( ReturnType < typeof this . choiceUI > | ReturnType < typeof this . taskUI > ) [ ] )
292284 }
293285
294286 private validateStepsIfNeeded ( steps : ReturnType < typeof this . wizardSteps > ) : WizardStep [ ] {
@@ -412,18 +404,18 @@ export default class Guide extends React.PureComponent<Props, State> {
412404 this . setState ( { isRunning : false } )
413405 }
414406
415- private runAction ( ) : WizardProps [ "rightButtons" ] [ number ] {
416- return (
417- ! this . hasRemainingChoices ( ) && {
407+ private runAction ( ) : ButtonProps | void {
408+ if ( this . hasRemainingChoices ( ) ) {
409+ return {
418410 className : "kui--guidebook-run" ,
419411 onClick : this . state . isRunning ? this . stopRun : this . startRun ,
420412 children : strings ( this . state . isRunning ? "Stop" : "Run" ) ,
421413 isDisabled : this . hasRemainingChoices ( ) , // ??? this does not seem to take...
422414 }
423- )
415+ }
424416 }
425417
426- private actions ( ) : Partial < WizardProps [ "rightButtons" ] > {
418+ private actions ( ) : ButtonProps [ ] | undefined {
427419 // return [this.runAction()].filter(Boolean)
428420 return undefined
429421 }
@@ -438,7 +430,7 @@ export default class Guide extends React.PureComponent<Props, State> {
438430 < div className = "kui--wizard" >
439431 < div className = "kui--wizard-main-content" >
440432 < Wizard
441- key = { this . state . isRunning && v4 ( ) }
433+ key = { this . state . isRunning ? v4 ( ) : undefined }
442434 boxShadow
443435 hideClose
444436 steps = { steps }
@@ -462,7 +454,7 @@ export default class Guide extends React.PureComponent<Props, State> {
462454 public render ( ) {
463455 try {
464456 if ( ! this . state || ! this . state . frontier ) {
465- return < React . Fragment />
457+ return < Loading />
466458 } else if ( this . state . error ) {
467459 return "Internal error"
468460 } else if ( this . state . frontier . length === 0 ) {
0 commit comments