Skip to content

Commit ad8cd03

Browse files
committed
Re-worked how the process to progress display translation works. Fixed bugs.
1 parent 9605deb commit ad8cd03

6 files changed

Lines changed: 100 additions & 99 deletions

File tree

src/events/context.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@ export enum Event {
1313
SUB_PROCESS_FINISH = 'sub_process_finish',
1414
}
1515

16+
export enum ProcessName {
17+
PLAN = 'plan',
18+
APPLY = 'apply'
19+
}
20+
21+
export enum SubProcessName {
22+
PARSE = 'parse',
23+
INITIALIZE_PLUGINS = 'initialize_plugins',
24+
VALIDATE = 'validate',
25+
GENERATE_PLAN = 'generate_plan',
26+
APPLY_RESOURCE = 'apply_resource',
27+
}
28+
1629
export const ctx = new class {
1730
emitter: EventEmitter;
1831

@@ -55,12 +68,12 @@ export const ctx = new class {
5568
this.emitter.emit(Event.PROCESS_FINISH, name);
5669
}
5770

58-
subprocessStarted(name: string, processName: string) {
59-
this.emitter.emit(Event.SUB_PROCESS_START, name, processName);
71+
subprocessStarted(name: string) {
72+
this.emitter.emit(Event.SUB_PROCESS_START, name);
6073
}
6174

62-
subprocessFinished(name: string, processName: string) {
63-
this.emitter.emit(Event.SUB_PROCESS_FINISH, name, processName);
75+
subprocessFinished(name: string) {
76+
this.emitter.emit(Event.SUB_PROCESS_FINISH, name);
6477
}
6578

6679
async subprocess<T>(name: string, run: () => Promise<T>): Promise<T> {

src/orchestrators/plan.ts

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { PlanResponseData } from 'codify-schemas';
22

33
import { Project } from '../entities/project.js';
4-
import { ctx } from '../events/context.js';
4+
import { ctx, ProcessName, SubProcessName } from '../events/context.js';
55
import { Parser } from '../parser/index.js';
66
import { PluginCollection } from '../plugins/plugin-collection.js';
77

@@ -11,47 +11,38 @@ interface PlanOchestratorResponse {
1111
project: Project;
1212
}
1313

14-
export enum PlanStatus {
15-
GENERATE_PLAN = 'generate_plan',
16-
INITIALIZE_PLUGINS = 'initalize_plugins',
17-
PARSE = 'parse',
18-
PLAN = 'plan',
19-
VALIDATE = 'validate',
20-
}
21-
2214
export const PlanOrchestrator = {
2315
async run(path: string, destroyPlugins = true): Promise<PlanOchestratorResponse> {
24-
ctx.processStarted(PlanStatus.PLAN)
16+
ctx.processStarted(ProcessName.PLAN)
2517

26-
ctx.subprocessStarted(PlanStatus.PARSE, PlanStatus.PLAN);
18+
ctx.subprocessStarted(SubProcessName.PARSE);
2719
const project = await Parser.parseProject(path);
28-
ctx.subprocessFinished(PlanStatus.PARSE, PlanStatus.PLAN);
20+
ctx.subprocessFinished(SubProcessName.PARSE);
2921

30-
ctx.subprocessStarted(PlanStatus.INITIALIZE_PLUGINS, PlanStatus.PLAN)
22+
ctx.subprocessStarted(SubProcessName.INITIALIZE_PLUGINS)
3123
const pluginCollection = new PluginCollection();
3224
const dependencyMap = await pluginCollection.initialize(project);
33-
ctx.subprocessFinished(PlanStatus.INITIALIZE_PLUGINS, PlanStatus.PLAN)
25+
ctx.subprocessFinished(SubProcessName.INITIALIZE_PLUGINS)
3426

35-
ctx.subprocessStarted(PlanStatus.VALIDATE, PlanStatus.PLAN)
27+
ctx.subprocessStarted(SubProcessName.VALIDATE)
3628
project.validateWithResourceMap(dependencyMap);
3729
project.resolveResourceDependencies(dependencyMap);
3830

3931
const validationResults = await pluginCollection.validate(project);
4032
project.handlePluginResourceValidationResults(validationResults);
4133
project.calculateEvaluationOrder();
42-
ctx.subprocessFinished(PlanStatus.VALIDATE, PlanStatus.PLAN)
34+
ctx.subprocessFinished(SubProcessName.VALIDATE)
4335

4436

45-
ctx.subprocessStarted(PlanStatus.GENERATE_PLAN, PlanStatus.PLAN)
37+
ctx.subprocessStarted(SubProcessName.GENERATE_PLAN)
4638
const plan = await pluginCollection.getPlan(project);
47-
ctx.subprocessFinished(PlanStatus.GENERATE_PLAN, PlanStatus.PLAN)
48-
39+
ctx.subprocessFinished(SubProcessName.GENERATE_PLAN)
4940

5041
if (destroyPlugins) {
5142
await pluginCollection.destroy();
5243
}
5344

54-
ctx.processFinished(PlanStatus.PLAN)
45+
ctx.processFinished(ProcessName.PLAN)
5546

5647
return {
5748
plan,

src/ui/components/default-component.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ export function DefaultComponent(props: {
2222
useEffect(() => {
2323
emitter.on(RenderEvent.STATE_TRANSITION, (obj) => {
2424
switch (obj.nextState) {
25-
case RenderState.GENERATING_PLAN: {
26-
setProgressState(obj.progressState);
27-
setState(obj.nextState);
28-
break;
29-
}
30-
3125
case RenderState.DISPLAY_PLAN: {
3226
setPlan(obj.plan);
3327
setState(obj.nextState);
@@ -45,11 +39,11 @@ export function DefaultComponent(props: {
4539
}
4640
})
4741

48-
emitter.once(RenderEvent.LOG, (newValue: string) => {
42+
emitter.on(RenderEvent.LOG, (newValue: string) => {
4943
setStaticOutput([...newValue]);
5044
});
5145

52-
emitter.on(RenderEvent.PROCESS_UPDATE, (state: ProgressState) => {
46+
emitter.on(RenderEvent.PROGRESS_UPDATE, (state: ProgressState) => {
5347
setProgressState(structuredClone(state));
5448
});
5549
}, []);

src/ui/components/progress/progress-display.tsx

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,47 @@ export enum ProgressStatus {
88
}
99

1010
export interface ProgressState {
11-
label: string,
11+
name: string,
12+
label: string;
1213
status: ProgressStatus;
13-
subProgress: ProgressState[] | null,
14+
subProgresses: Array<{
15+
name: string,
16+
label: string;
17+
status: ProgressStatus;
18+
}> | null;
1419
}
1520

1621
export function ProgressDisplay(
1722
props: {
1823
progress: ProgressState,
1924
}
2025
) {
21-
const { label, status, subProgress } = props.progress;
26+
const { label, status, subProgresses } = props.progress;
2227

2328
return <Box flexDirection="column">
2429
{
2530
status === ProgressStatus.IN_PROGRESS
2631
? <Spinner label={label}/>
2732
: <StatusMessage variant="success">{label}</StatusMessage>
2833
}
29-
{
30-
subProgress && <Box flexDirection="column" marginLeft={2}>
31-
<SubProgressDisplay subProgresses={subProgress}/>
32-
</Box>
33-
}
34+
<Box flexDirection="column" marginLeft={2}>
35+
<SubProgressDisplay subProgresses={subProgresses}/>
36+
</Box>
3437
</Box>
3538
}
3639

3740
export function SubProgressDisplay(
3841
props: {
39-
subProgresses: ProgressState[],
42+
subProgresses: ProgressState['subProgresses'],
4043
}
4144
) {
4245
const { subProgresses } = props;
4346

4447
return <>{
45-
subProgresses.map((s, idx) => <Box>
46-
{
47-
s.status === ProgressStatus.IN_PROGRESS
48-
? <Spinner key={idx} label={s.label}/>
49-
: <StatusMessage key={idx} variant="success">{s.label}</StatusMessage>
50-
}
51-
{
52-
s.subProgress && <Box flexDirection="column" marginLeft={2}>
53-
<SubProgressDisplay subProgresses={s.subProgress}/>
54-
</Box>
55-
}
56-
</Box>)
57-
}</>
48+
subProgresses && subProgresses.map((s, idx) =>
49+
s.status === ProgressStatus.IN_PROGRESS
50+
? <Spinner key={idx} label={s.label}/>
51+
: <StatusMessage key={idx} variant="success">{s.label}</StatusMessage>
52+
)
53+
}</>
5854
}

src/ui/reporters/default-reporter.tsx

Lines changed: 51 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,35 @@ import { render } from 'ink';
33
import { EventEmitter } from 'node:events';
44
import React from 'react';
55

6-
import { ctx, Event } from '../../events/context.js';
6+
import { ctx, Event, ProcessName, SubProcessName } from '../../events/context.js';
77
import { DefaultComponent } from '../components/default-component.js';
8+
import { ProgressState, ProgressStatus } from '../components/progress/progress-display.js';
89
import { DisplayPlanStateTransition, RenderEvent, RenderState, Reporter } from './reporter.js';
910

11+
const ProgressLabelMapping = {
12+
[ProcessName.APPLY]: 'Applying plan...',
13+
[ProcessName.PLAN]: 'Generating plan...',
14+
[SubProcessName.APPLY_RESOURCE]: 'Applying resource',
15+
[SubProcessName.GENERATE_PLAN]: 'Generating plan',
16+
[SubProcessName.INITIALIZE_PLUGINS]: 'Initializing plugins',
17+
[SubProcessName.PARSE]: 'Parsing configs',
18+
[SubProcessName.VALIDATE]: 'Validating configs',
19+
}
20+
1021
export class DefaultReporter implements Reporter {
1122

1223
private renderEmitter = new EventEmitter();
13-
private staticOutput = new Array<any>()
24+
private staticOutput = new Array<string>()
25+
private progressState: ProgressState | null = null
1426

1527
constructor() {
1628
ctx.on(Event.OUTPUT, (...args) => this.renderLog(...args));
17-
ctx.on(Event.PROCESS_START, (name) => this.onProcessEvent(name))
29+
ctx.on(Event.PROCESS_START, (name) => this.onProcessStartEvent(name))
1830
ctx.on(Event.PROCESS_FINISH, (name) => this.onProcessFinishEvent(name))
19-
ctx.on(Event.SUB_PROCESS_START, (name, processName) => this.onSubprocessStartEvent(name, processName));
20-
ctx.on(Event.SUB_PROCESS_FINISH, (name, processName) => this.onSubprocessFinishEvent(name, processName))
31+
ctx.on(Event.SUB_PROCESS_START, (name) => this.onSubprocessStartEvent(name));
32+
ctx.on(Event.SUB_PROCESS_FINISH, (name) => this.onSubprocessFinishEvent(name))
2133

2234
render(<DefaultComponent emitter={this.renderEmitter}/>)
23-
2435
}
2536

2637
async promptConfirmation(): Promise<boolean> {
@@ -44,67 +55,63 @@ export class DefaultReporter implements Reporter {
4455
} as DisplayPlanStateTransition);
4556
}
4657

47-
private renderLog(...args: unknown[]) {
58+
private renderLog(...args: string[]) {
4859
this.staticOutput.push(...args);
4960
this.renderEmitter.emit(RenderEvent.LOG, this.staticOutput);
5061
}
5162

52-
private onProcessEvent(name: string): void {
53-
this.processState.process.push({
63+
private onProcessStartEvent(name: ProcessName): void {
64+
const label = ProgressLabelMapping[name];
65+
66+
this.progressState = {
5467
name,
55-
status: ProcessStatus.IN_PROGRESS,
56-
subprocess: [],
57-
})
68+
label,
69+
status: ProgressStatus.IN_PROGRESS,
70+
subProgresses: [],
71+
};
5872

59-
this.renderLog(`${name} started`)
60-
this.renderEmitter.emit(RenderEvent.PROCESS_UPDATE, this.processState);
73+
this.renderLog(`${label} started`)
74+
this.renderEmitter.emit(RenderEvent.PROGRESS_UPDATE, this.progressState);
6175
}
6276

63-
private onProcessFinishEvent(name: string): void {
64-
const process = this.processState.process
65-
.find((process) => process.name === name);
66-
if (!process) {
67-
return;
68-
}
77+
private onProcessFinishEvent(name: ProcessName): void {
78+
const label = ProgressLabelMapping[name];
6979

70-
process.status = ProcessStatus.FINISHED;
80+
this.progressState!.status = ProgressStatus.FINISHED;
7181

72-
this.renderLog(`${name} finished successfully`)
73-
this.renderEmitter.emit(RenderEvent.PROCESS_UPDATE, this.processState.process);
82+
this.renderLog(`${label} finished successfully`)
83+
this.renderEmitter.emit(RenderEvent.PROGRESS_UPDATE, this.progressState);
7484

7585
}
7686

77-
private onSubprocessStartEvent(name: string, processName: string): void {
78-
const process = this.processState.process
79-
.find((process) => process.name === processName);
80-
81-
if (!process) return;
87+
private onSubprocessStartEvent(name: SubProcessName): void {
88+
const label = ProgressLabelMapping[name];
8289

83-
process.subprocess.push({
90+
this.progressState?.subProgresses?.push({
8491
name,
85-
status: ProcessStatus.IN_PROGRESS,
86-
})
92+
label,
93+
status: ProgressStatus.IN_PROGRESS,
94+
});
8795

88-
this.renderLog(`${name} started`)
89-
this.renderEmitter.emit(RenderEvent.PROCESS_UPDATE, this.processState);
96+
this.renderLog(`${label} started`)
97+
this.renderEmitter.emit(RenderEvent.PROGRESS_UPDATE, this.progressState);
9098
}
9199

92-
private onSubprocessFinishEvent(name: string, processName: string): void {
93-
const process = this.processState.process
94-
.find((process) => process.name === processName);
95-
if (!process) {
96-
return;
97-
}
100+
private onSubprocessFinishEvent(name: SubProcessName): void {
101+
const label = ProgressLabelMapping[name];
102+
103+
const subProgress = this.progressState
104+
?.subProgresses
105+
?.find((p) => p.name === name);
98106

99-
const subprocess = process.subprocess.find((subprocess) => subprocess.name === name)
100-
if (!subprocess) {
107+
if (!subProgress) {
101108
return;
102109
}
103110

104-
subprocess.status = ProcessStatus.FINISHED;
111+
subProgress.status = ProgressStatus.FINISHED;
105112

106-
this.renderLog(`${name} finished successfully`)
107-
this.renderEmitter.emit(RenderEvent.PROCESS_UPDATE, this.processState);
113+
this.renderLog(`${label} finished successfully`)
114+
this.renderEmitter.emit(RenderEvent.PROGRESS_UPDATE, this.progressState);
108115
}
109116

110117
}

src/ui/reporters/reporter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { PlanResponseData } from 'codify-schemas';
33
export enum RenderEvent {
44
STATE_TRANSITION = 'stateTransition',
55
LOG = 'log',
6-
PROCESS_UPDATE = 'processUpdate',
6+
PROGRESS_UPDATE = 'progressUpdate',
77
PROMPT_RESULT = 'promptResult'
88
}
99

0 commit comments

Comments
 (0)