|
16 | 16 |
|
17 | 17 | import React from 'react'
|
18 | 18 | import { i18n } from '@kui-shell/core'
|
19 |
| - |
20 |
| -import { Graph, blocks, progress } from '../code/graph' |
21 |
| - |
22 |
| -import { ProgressStepState, statusFromStatusVector } from '../../../ProgressStepper' |
23 |
| -import { subscribeToLinkUpdates, unsubscribeToLinkUpdates } from '../../../LinkStatus' |
| 19 | +import { ProgressVariant } from '@patternfly/react-core' |
24 | 20 |
|
25 | 21 | import { State as WizardState } from '.'
|
26 | 22 |
|
27 |
| -import { ProgressVariant } from '@patternfly/react-core' |
| 23 | +import { |
| 24 | + ReadinessHandler, |
| 25 | + emitCodeBlockReadiness, |
| 26 | + onGetCodeBlockReadiness, |
| 27 | + offGetCodeBlockReadiness |
| 28 | +} from '../../../../Views/Terminal/Block/CodeBlockEvents' |
| 29 | + |
| 30 | +import { OrderedGraph, blocks, progress } from '../code/graph' |
| 31 | +import { ProgressStepState } from '../../../ProgressStepper' |
28 | 32 |
|
29 | 33 | const PatternFlyProgress = React.lazy(() => import('@patternfly/react-core').then(_ => ({ default: _.Progress })))
|
30 | 34 |
|
31 | 35 | const strings = i18n('plugin-client-common', 'code')
|
32 | 36 |
|
| 37 | +type Status = ProgressStepState['status'] |
| 38 | + |
33 | 39 | type Props = Pick<WizardState, 'choices'> & {
|
34 | 40 | /** The tasks to be accomplished */
|
35 |
| - codeBlocks: Graph |
36 |
| -} |
37 |
| - |
38 |
| -type Status = ProgressStepState['status'] |
| 41 | + codeBlocks: OrderedGraph |
39 | 42 |
|
40 |
| -interface State { |
41 | 43 | /** The key is a codeBlockId */
|
42 | 44 | status: Record<string, Status>
|
43 | 45 | }
|
44 | 46 |
|
| 47 | +type State = ReturnType<typeof progress> & { |
| 48 | + nextCodeBlocks: string[] |
| 49 | +} |
| 50 | + |
45 | 51 | export default class Progress extends React.PureComponent<Props, State> {
|
| 52 | + private readonly cleaners: (() => void)[] = [] |
| 53 | + |
46 | 54 | public constructor(props: Props) {
|
47 | 55 | super(props)
|
48 | 56 |
|
49 |
| - this.state = { |
50 |
| - status: {} |
51 |
| - } |
| 57 | + this.state = Progress.getDerivedStateFromProps(props) |
52 | 58 | }
|
53 | 59 |
|
54 |
| - private readonly _statusUpdateHandler = (statusVector: number[], codeBlockId: string) => { |
55 |
| - const status = statusFromStatusVector(statusVector, false) |
| 60 | + public static getDerivedStateFromProps(props: Props, state?: State) { |
| 61 | + const prog = progress(props.codeBlocks, props.status, props.choices) |
| 62 | + |
| 63 | + const allCodeBlocks = blocks(props.codeBlocks) |
| 64 | + if (!state) { |
| 65 | + // initialize all blocks as not ready |
| 66 | + allCodeBlocks.forEach(_ => emitCodeBlockReadiness(_.id, false)) |
| 67 | + } |
| 68 | + |
| 69 | + const nextCodeBlocks = allCodeBlocks.filter(_ => prog.nextOrdinals.includes(_.order)).map(_ => _.id) |
| 70 | + |
| 71 | + if (state) { |
| 72 | + const noLongerReady = state.nextCodeBlocks.filter(_ => !nextCodeBlocks.includes(_)) |
| 73 | + noLongerReady.forEach(id => emitCodeBlockReadiness(id, false)) |
| 74 | + } |
| 75 | + nextCodeBlocks.forEach(id => emitCodeBlockReadiness(id, true)) |
56 | 76 |
|
57 |
| - this.updateStatus(codeBlockId, status) |
| 77 | + return Object.assign({}, prog, { nextCodeBlocks }) |
58 | 78 | }
|
59 | 79 |
|
60 |
| - private updateStatus(codeBlockId: string, status: Status) { |
61 |
| - this.setState(curState => { |
62 |
| - curState.status[codeBlockId] = status |
63 |
| - return { |
64 |
| - status: Object.assign({}, curState.status) |
65 |
| - } |
66 |
| - }) |
| 80 | + private readonly _onGetReadiness = (handler: ReadinessHandler, codeBlockId: string) => { |
| 81 | + const ready = this.state.nextCodeBlocks.includes(codeBlockId) |
| 82 | + handler(ready) |
67 | 83 | }
|
68 | 84 |
|
69 | 85 | public componentDidMount() {
|
70 |
| - blocks(this.props.codeBlocks, 'all').forEach(_ => { |
71 |
| - subscribeToLinkUpdates(_.id, this._statusUpdateHandler) |
| 86 | + blocks(this.props.codeBlocks).forEach(({ id }) => { |
| 87 | + onGetCodeBlockReadiness(id, this._onGetReadiness) |
| 88 | + this.cleaners.push(() => offGetCodeBlockReadiness(id, this._onGetReadiness)) |
72 | 89 | })
|
73 | 90 | }
|
74 | 91 |
|
75 | 92 | public componentWillUnmount() {
|
76 |
| - blocks(this.props.codeBlocks, 'all').forEach(_ => { |
77 |
| - unsubscribeToLinkUpdates(_.id, this._statusUpdateHandler) |
78 |
| - }) |
79 |
| - } |
80 |
| - |
81 |
| - private get nSteps() { |
82 |
| - return progress(this.props.codeBlocks, undefined, this.props.choices).nTotal |
83 |
| - } |
84 |
| - |
85 |
| - private counts() { |
86 |
| - return progress(this.props.codeBlocks, this.state.status, this.props.choices) |
| 93 | + this.cleaners.forEach(_ => _()) |
87 | 94 | }
|
88 | 95 |
|
89 | 96 | public render() {
|
90 |
| - const { nDone, nError } = this.counts() |
| 97 | + const { nDone, nError, nTotal } = this.state |
91 | 98 |
|
92 | 99 | const title = strings('Completed tasks')
|
93 | 100 | const label =
|
94 | 101 | nError > 0
|
95 |
| - ? strings(nError === 1 ? 'xOfyFailingz' : 'xOfyFailingsz', nDone, nError, this.nSteps) |
96 |
| - : strings('xOfy', nDone, this.nSteps) |
| 102 | + ? strings(nError === 1 ? 'xOfyFailingz' : 'xOfyFailingsz', nDone, nError, nTotal) |
| 103 | + : strings('xOfy', nDone, nTotal) |
97 | 104 |
|
98 |
| - const variant = nDone === this.nSteps ? ProgressVariant.success : nError > 0 ? ProgressVariant.danger : undefined |
| 105 | + const variant = nDone === nTotal ? ProgressVariant.success : nError > 0 ? ProgressVariant.danger : undefined |
99 | 106 |
|
100 | 107 | return (
|
101 | 108 | <PatternFlyProgress
|
102 | 109 | aria-label="wizard progress"
|
103 | 110 | className="kui--wizard-progress"
|
104 | 111 | min={0}
|
105 |
| - max={this.nSteps} |
| 112 | + max={nTotal} |
106 | 113 | value={nDone}
|
107 | 114 | title={title}
|
108 | 115 | label={label}
|
|
0 commit comments