Skip to content

Commit ef2523d

Browse files
committed
feat(course-setup): add CLI ping step controlled by feature flag
Introduce a new "Test CLI connection" setup step that replaces the previous "Push empty commit" step when the `canViewCLIPingFlow` feature flag is enabled. Update related UI text and instructions to reflect this new flow, including the addition of a reusable command component for running CLI connection tests. This change enables a smoother onboarding experience for users with access to experimental CLI ping functionality, controlled via a feature flag to allow gradual rollout without impacting existing users.
1 parent c9f5c5f commit ef2523d

13 files changed

Lines changed: 148 additions & 38 deletions

File tree

app/components/course-page/course-stage-step/first-stage-your-task-card/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import CoursePageStateService from 'codecrafters-frontend/services/course-page-s
44
import RepositoryModel from 'codecrafters-frontend/models/repository';
55
import Store from '@ember-data/store';
66
import type CourseStageStep from 'codecrafters-frontend/utils/course-page-step-list/course-stage-step';
7+
import type FeatureFlagsService from 'codecrafters-frontend/services/feature-flags';
78
import type { StepDefinition } from 'codecrafters-frontend/components/step-list';
89
import { action } from '@ember/object';
910
import { service } from '@ember/service';
@@ -40,6 +41,14 @@ class UncommentCodeStep extends BaseStep implements StepDefinition {
4041
}
4142
}
4243

44+
class TestCodeStep extends BaseStep implements StepDefinition {
45+
id = 'submit-code';
46+
47+
get titleMarkdown() {
48+
return 'Run tests';
49+
}
50+
}
51+
4352
class SubmitCodeStep extends BaseStep implements StepDefinition {
4453
id = 'submit-code';
4554

@@ -51,6 +60,7 @@ class SubmitCodeStep extends BaseStep implements StepDefinition {
5160
export default class FirstStageYourTaskCard extends Component<Signature> {
5261
@service declare analyticsEventTracker: AnalyticsEventTrackerService;
5362
@service declare coursePageState: CoursePageStateService;
63+
@service declare featureFlags: FeatureFlagsService;
5464
@service declare store: Store;
5565

5666
get filename() {
@@ -70,7 +80,9 @@ export default class FirstStageYourTaskCard extends Component<Signature> {
7080
get steps() {
7181
return [
7282
new UncommentCodeStep(this.args.currentStep.repository, this.stepsAreComplete),
73-
new SubmitCodeStep(this.args.currentStep.repository, this.stepsAreComplete),
83+
this.featureFlags.canViewCLIPingFlow
84+
? new TestCodeStep(this.args.currentStep.repository, this.stepsAreComplete)
85+
: new SubmitCodeStep(this.args.currentStep.repository, this.stepsAreComplete),
7486
];
7587
}
7688

app/components/course-page/course-stage-step/first-stage-your-task-card/submit-code-step.hbs

Lines changed: 36 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,49 @@
1-
<div class="mb-3">
2-
<div class="prose prose-compact dark:prose-invert mb-3">
3-
First, run this command to commit your changes:
1+
{{#if this.featureFlags.canViewCLIPingFlow}}
2+
<div>
3+
<CopyableTerminalCommand @commands={{array "codecrafters test"}} class="mb-1.5" />
4+
5+
<div class="flex items-center gap-0.5 pl-0.5">
6+
{{svg-jar "question-mark-circle" class="w-3 h-3 fill-current text-blue-500"}}
7+
8+
{{! TODO: Change troubleshooting link }}
9+
<span class="text-blue-500 text-xs underline font-medium">
10+
<a href="#" {{on "click" (fn (mut this.isCommitModalOpen) true)}}>Troubleshoot</a>
11+
</span>
12+
</div>
413
</div>
14+
{{else}}
15+
<div class="mb-3">
16+
<div class="prose prose-compact dark:prose-invert mb-3">
17+
First, run this command to commit your changes:
18+
</div>
519

6-
<CopyableTerminalCommand @commands={{array 'git commit -am "[any message]"'}} class="mb-1.5" />
20+
<CopyableTerminalCommand @commands={{array 'git commit -am "[any message]"'}} class="mb-1.5" />
721

8-
<div class="flex items-center gap-0.5 pl-0.5">
9-
{{svg-jar "question-mark-circle" class="w-3 h-3 fill-current text-blue-500"}}
22+
<div class="flex items-center gap-0.5 pl-0.5">
23+
{{svg-jar "question-mark-circle" class="w-3 h-3 fill-current text-blue-500"}}
1024

11-
<span class="text-blue-500 text-xs underline font-medium">
12-
<a href="#" {{on "click" (fn (mut this.isCommitModalOpen) true)}}>Troubleshoot</a>
13-
</span>
25+
<span class="text-blue-500 text-xs underline font-medium">
26+
<a href="#" {{on "click" (fn (mut this.isCommitModalOpen) true)}}>Troubleshoot</a>
27+
</span>
28+
</div>
1429
</div>
15-
</div>
1630

17-
<div>
18-
<div class="prose prose-compact dark:prose-invert mb-3">
19-
Next, run this command to push your changes:
20-
</div>
31+
<div>
32+
<div class="prose prose-compact dark:prose-invert mb-3">
33+
Next, run this command to push your changes:
34+
</div>
2135

22-
<CopyableTerminalCommand @commands={{array "git push origin master"}} class="mb-1.5" />
36+
<CopyableTerminalCommand @commands={{array "git push origin master"}} class="mb-1.5" />
2337

24-
<div class="flex items-center gap-0.5 pl-0.5">
25-
{{svg-jar "question-mark-circle" class="w-3 h-3 fill-current text-blue-500"}}
38+
<div class="flex items-center gap-0.5 pl-0.5">
39+
{{svg-jar "question-mark-circle" class="w-3 h-3 fill-current text-blue-500"}}
2640

27-
<span class="text-blue-500 text-xs underline font-medium">
28-
<a href="#" {{on "click" (fn (mut this.isPushModalOpen) true)}}>Troubleshoot</a>
29-
</span>
41+
<span class="text-blue-500 text-xs underline font-medium">
42+
<a href="#" {{on "click" (fn (mut this.isPushModalOpen) true)}}>Troubleshoot</a>
43+
</span>
44+
</div>
3045
</div>
31-
</div>
46+
{{/if}}
3247

3348
{{!-- <div class="prose dark:prose-invert">
3449
<p class={{if @isComplete "line-through"}}>

app/components/course-page/course-stage-step/test-runner-card/run-tests-instructions.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import type Owner from '@ember/owner';
44
import { tracked } from '@glimmer/tracking';
55
import type { CopyableTerminalCommandVariant } from 'codecrafters-frontend/components/copyable-terminal-command-with-variants';
66
import type CourseStageStep from 'codecrafters-frontend/utils/course-page-step-list/course-stage-step';
7+
import { service } from '@ember/service';
8+
import type FeatureFlagsService from 'codecrafters-frontend/services/feature-flags';
79

810
interface Signature {
911
Element: HTMLDivElement;
@@ -15,6 +17,8 @@ interface Signature {
1517
}
1618

1719
export default class RunTestsInstructions extends Component<Signature> {
20+
@service declare featureFlags: FeatureFlagsService;
21+
1822
@tracked selectedCommandVariant: CopyableTerminalCommandVariant;
1923

2024
constructor(owner: Owner, args: Signature['Args']) {
@@ -46,6 +50,10 @@ export default class RunTestsInstructions extends Component<Signature> {
4650
}
4751

4852
get recommendedClientType() {
53+
if (this.featureFlags.canViewCLIPingFlow) {
54+
return 'cli';
55+
}
56+
4957
if (this.args.currentStep.courseStage.isFirst || this.args.currentStep.courseStage.isSecond) {
5058
return 'git';
5159
} else {

app/components/course-page/setup-step-complete-modal.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ export default class SetupStepCompleteModalComponent extends Component<Signature
5252
async handleDidInsert() {
5353
console.log('handleDidInsert');
5454
// Pre-cache the workflow animation GIF to avoid flickering when it loads.
55+
fetch('https://codecrafters.io/images/overview/workflow-animation-3.gif', { mode: 'no-cors' });
56+
57+
// TODO: Remove this once can-view-cli-ping-flow feature flag is the default
5558
fetch('https://codecrafters.io/images/overview/workflow-animation-2.gif', { mode: 'no-cors' });
5659
}
5760

app/components/course-page/setup-step-complete-modal/workflow-tutorial-step2-screen.hbs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,40 @@
55

66
<div class="px-3 sm:px-6 py-6 bg-gray-50 dark:bg-gray-925 rounded-sm border border-gray-200 dark:border-gray-700 mb-6">
77
<div class="mb-4 font-bold text-lg text-gray-700 dark:text-gray-100 text-center text-pretty">
8-
`git push` to submit
8+
{{#if this.featureFlags.canViewCLIPingFlow}}
9+
Run `codecrafters test`
10+
{{else}}
11+
`git push` to submit
12+
{{/if}}
913
</div>
1014

1115
<div class="prose prose-sm dark:prose-invert mb-4 text-center text-pretty">
1216
<p>
13-
When you're ready to test, commit your changes and run `git push`.
17+
{{#if this.featureFlags.canViewCLIPingFlow}}
18+
Once you're ready to test your code, simply run `codecrafters test`.
19+
{{else}}
20+
When you're ready to test, commit your changes and run `git push`.
21+
{{/if}}
1422
</p>
1523
</div>
1624

17-
{{! Note: This image is pre-cached in SetupStepCompleteModal.handleDidInsert }}
18-
<div class="w-full h-48 mb-4 bg-[url(https://codecrafters.io/images/overview/workflow-animation-2.gif)] bg-cover bg-center rounded-sm">
19-
</div>
25+
{{#if this.featureFlags.canViewCLIPingFlow}}
26+
{{! Note: This image is pre-cached in SetupStepCompleteModal.handleDidInsert }}
27+
<div class="w-full h-48 mb-4 bg-[url(https://codecrafters.io/images/overview/workflow-animation-3.gif)] bg-cover bg-center rounded-sm">
28+
</div>
29+
{{else}}
30+
{{! Note: This image is pre-cached in SetupStepCompleteModal.handleDidInsert }}
31+
<div class="w-full h-48 mb-4 bg-[url(https://codecrafters.io/images/overview/workflow-animation-2.gif)] bg-cover bg-center rounded-sm">
32+
</div>
33+
{{/if}}
2034

2135
<div class="prose prose-sm dark:prose-invert text-center text-pretty">
2236
<p>
23-
Your code will be submitted to CodeCrafters and you'll see feedback in your browser.
37+
{{#if this.featureFlags.canViewCLIPingFlow}}
38+
You'll receive instant feedback in both your terminal and browser.
39+
{{else}}
40+
Your code will be submitted to CodeCrafters and you'll see feedback in your browser.
41+
{{/if}}
2442
</p>
2543
</div>
2644
</div>

app/components/course-page/setup-step-complete-modal/workflow-tutorial-step2-screen.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Component from '@glimmer/component';
2+
import FeatureFlagsService from 'codecrafters-frontend/services/feature-flags';
23
import type SetupStep from 'codecrafters-frontend/utils/course-page-step-list/setup-step';
4+
import { service } from '@ember/service';
35

46
interface Signature {
57
Element: HTMLDivElement;
@@ -11,7 +13,9 @@ interface Signature {
1113
};
1214
}
1315

14-
export default class WorkflowTutorialStep2ScreenComponent extends Component<Signature> {}
16+
export default class WorkflowTutorialStep2ScreenComponent extends Component<Signature> {
17+
@service declare featureFlags: FeatureFlagsService;
18+
}
1519

1620
declare module '@glint/environment-ember-loose/registry' {
1721
export default interface Registry {

app/components/course-page/setup-step/repository-setup-card/index.hbs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@
1919
<CoursePage::SetupStep::RepositorySetupCard::CloneRepositoryStep @repository={{@repository}} />
2020
{{else if (eq context.step.id "push-empty-commit")}}
2121
<CoursePage::SetupStep::RepositorySetupCard::PushEmptyCommitStep @repository={{@repository}} />
22+
{{else if (eq context.step.id "test-cli-connection")}}
23+
<CoursePage::SetupStep::RepositorySetupCard::TestCliConnectionStep @repository={{@repository}} />
2224
{{/if}}
2325
</StepList>
2426

2527
{{#if this.isComplete}}
2628
<div class="mt-4 prose dark:prose-invert">
2729
<span class="text-xl mr-1">🎉</span>
28-
Git push received! The first stage is now activated.
30+
31+
{{#if this.featureFlags.canViewCLIPingFlow}}
32+
The first stage is now activated.
33+
{{else}}
34+
Git push received! The first stage is now activated.
35+
{{/if}}
2936
</div>
3037

3138
<PrimaryLinkButton

app/components/course-page/setup-step/repository-setup-card/index.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { service } from '@ember/service';
33
import type RepositoryModel from 'codecrafters-frontend/models/repository';
44
import type CoursePageStateService from 'codecrafters-frontend/services/course-page-state';
55
import type { StepDefinition } from 'codecrafters-frontend/components/step-list';
6+
import type FeatureFlagsService from 'codecrafters-frontend/services/feature-flags';
67

78
export interface Signature {
89
Element: HTMLDivElement;
@@ -30,6 +31,14 @@ class CloneRepositoryStepDefinition extends BaseStep implements StepDefinition {
3031
}
3132
}
3233

34+
class TestCliConnectionStepDefinition extends BaseStep implements StepDefinition {
35+
id = 'test-cli-connection';
36+
37+
get titleMarkdown() {
38+
return 'Test CLI connection';
39+
}
40+
}
41+
3342
class PushEmptyCommitStepDefinition extends BaseStep implements StepDefinition {
3443
id = 'push-empty-commit';
3544

@@ -40,6 +49,7 @@ class PushEmptyCommitStepDefinition extends BaseStep implements StepDefinition {
4049

4150
export default class RepositorySetupCard extends Component<Signature> {
4251
@service declare coursePageState: CoursePageStateService;
52+
@service declare featureFlags: FeatureFlagsService;
4353

4454
get isComplete() {
4555
return this.coursePageState.currentStep.status === 'complete';
@@ -48,7 +58,9 @@ export default class RepositorySetupCard extends Component<Signature> {
4858
get steps() {
4959
return [
5060
new CloneRepositoryStepDefinition(this.args.repository, this.isComplete),
51-
new PushEmptyCommitStepDefinition(this.args.repository, this.isComplete),
61+
this.featureFlags.canViewCLIPingFlow
62+
? new TestCliConnectionStepDefinition(this.args.repository, this.isComplete)
63+
: new PushEmptyCommitStepDefinition(this.args.repository, this.isComplete),
5264
];
5365
}
5466
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<CopyableTerminalCommand @commands={{array "curl https://codecrafters.io/install.sh | sh" "codecrafters ping"}} />
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import Component from '@glimmer/component';
2+
import type RepositoryModel from 'codecrafters-frontend/models/repository';
3+
4+
export interface Signature {
5+
Element: HTMLDivElement;
6+
7+
Args: {
8+
repository: RepositoryModel;
9+
};
10+
}
11+
12+
export default class TestCliConnectionStep extends Component<Signature> {}
13+
14+
declare module '@glint/environment-ember-loose/registry' {
15+
export default interface Registry {
16+
'CoursePage::SetupStep::RepositorySetupCard::TestCliConnectionStep': typeof TestCliConnectionStep;
17+
}
18+
}

0 commit comments

Comments
 (0)