Skip to content

Commit b1ed865

Browse files
authored
Merge pull request #3137 from codecrafters-io/arpan/cc-1939-change-extensions-configuration-ui
Add extension progress pill component and update extension card layout.
2 parents 7036d99 + 0964fe0 commit b1ed865

File tree

5 files changed

+75
-5
lines changed

5 files changed

+75
-5
lines changed

app/components/course-page/configure-extensions-modal/extension-card.hbs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@
66
data-test-course-extension-card
77
>
88
<div class="flex items-start justify-between mb-3">
9-
<div class="flex items-center flex-wrap gap-3 mr-2 mb-0.5">
9+
<div class="flex items-center flex-wrap gap-2 mr-2 mb-0.5">
1010
<div
1111
class="{{if this.optimisticValueForIsActivated 'text-teal-600 dark:text-teal-500' 'text-gray-800 dark:text-gray-50'}}
1212
font-bold text-xl tracking-tight"
1313
data-test-course-extension-name
1414
>
1515
{{@extension.name}}
1616
</div>
17-
<BetaCourseExtensionLabel />
17+
{{#if (eq this.progressPillType "completed")}}
18+
<Pill @color="green" data-test-extension-progress-pill>Completed</Pill>
19+
{{else if (eq this.progressPillType "in_progress")}}
20+
<Pill @color="yellow" data-test-extension-progress-pill>In Progress</Pill>
21+
{{/if}}
1822
</div>
1923
<div>
2024
<Toggle @isOn={{this.optimisticValueForIsActivated}} {{on "click" this.handleClick}} data-test-toggle-extension-button />

app/components/course-page/configure-extensions-modal/extension-card.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ export default class ExtensionCard extends Component<Signature> {
4242
}
4343
}
4444

45+
get progressPillType(): 'completed' | 'in_progress' | null {
46+
const stages = this.args.extension.sortedStages;
47+
const allComplete = stages.length > 0 && stages.every((stage) => this.args.repository.stageIsComplete(stage));
48+
const currentStageInExtension = this.args.repository.currentStage && stages.includes(this.args.repository.currentStage);
49+
50+
if (allComplete) return 'completed';
51+
if (currentStageInExtension) return 'in_progress';
52+
53+
return null;
54+
}
55+
4556
syncActivation = task({ keepLatest: true }, async (): Promise<void> => {
4657
if (this.unsavedIsActivatedValue === null) {
4758
return;

app/components/course-page/configure-extensions-modal/index.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
Extensions are sets of additional stages that can be added to your repository. You can add &amp; remove extensions at any time.
88
</AlertWithIcon>
99

10-
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6">
10+
<div class="grid grid-cols-1 gap-4 mb-6">
1111
{{#each @repository.course.sortedExtensions as |extension|}}
1212
<CoursePage::ConfigureExtensionsModal::ExtensionCard @extension={{extension}} @repository={{@repository}} />
1313
{{/each}}
@@ -22,7 +22,7 @@
2222
</div>
2323
</div>
2424

25-
<div class="grid grid-cols-1 gap-3 lg:grid-cols-2 mb-8">
25+
<div class="grid grid-cols-1 gap-3 mb-8">
2626
<RoadmapPage::SubmitCourseExtensionIdeaCard @course={{@repository.course}} />
2727

2828
{{#each this.orderedCourseExtensionIdeas as |courseExtensionIdea|}}

tests/acceptance/course-page/extensions/enable-extensions-test.js

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import catalogPage from 'codecrafters-frontend/tests/pages/catalog-page';
88
import coursePage from 'codecrafters-frontend/tests/pages/course-page';
99
import courseOverviewPage from 'codecrafters-frontend/tests/pages/course-overview-page';
1010
import createCourseExtensionIdeas from 'codecrafters-frontend/mirage/utils/create-course-extension-ideas';
11+
import percySnapshot from '@percy/ember';
1112
import testScenario from 'codecrafters-frontend/mirage/scenarios/test';
1213

1314
module('Acceptance | course-page | extensions | enable-extensions', function (hooks) {
@@ -135,4 +136,56 @@ module('Acceptance | course-page | extensions | enable-extensions', function (ho
135136

136137
assert.true(coursePage.configureExtensionsModal.isVisible, 'configure extensions modal is visible');
137138
});
139+
140+
test('progress pills show correct status for different extension states', async function (assert) {
141+
testScenario(this.server);
142+
signInAsStaff(this.owner, this.server);
143+
144+
let currentUser = this.server.schema.users.first();
145+
let python = this.server.schema.languages.findBy({ name: 'Python' });
146+
let course = this.server.schema.courses.findBy({ slug: 'dummy' });
147+
148+
let repository = this.server.create('repository', 'withBaseStagesCompleted', {
149+
course: course,
150+
language: python,
151+
user: currentUser,
152+
});
153+
154+
let extensions = course.extensions.models.sortBy('position');
155+
let extension1Stages = course.stages.models.filter((stage) => stage.primaryExtensionSlug === extensions[0].slug);
156+
let extension2Stages = course.stages.models.filter((stage) => stage.primaryExtensionSlug === extensions[1].slug);
157+
158+
extension1Stages.forEach((stage) => {
159+
this.server.create('submission', 'withStageCompletion', {
160+
repository,
161+
courseStage: stage,
162+
createdAt: repository.createdAt,
163+
});
164+
});
165+
166+
this.server.create('submission', 'withStageCompletion', {
167+
repository,
168+
courseStage: extension2Stages.sortBy('positionWithinExtension')[0],
169+
createdAt: repository.createdAt,
170+
});
171+
172+
await catalogPage.visit();
173+
await catalogPage.clickOnCourse('Build your own Dummy');
174+
await courseOverviewPage.adminPanel.clickOnStartCourse();
175+
await coursePage.sidebar.configureExtensionsToggles[0].click();
176+
await percySnapshot('Configure Extensions Modal - Progress Pills');
177+
178+
let cards = coursePage.configureExtensionsModal.extensionCards.toArray();
179+
180+
assert.true(cards[0].hasPill, 'Extension 1 has completed pill');
181+
assert.strictEqual(cards[0].pillText, 'Completed', 'Extension 1 pill shows "Completed"');
182+
assert.true(cards[1].hasPill, 'Extension 2 has in-progress pill');
183+
assert.strictEqual(cards[1].pillText, 'In Progress', 'Extension 2 pill shows "In Progress"');
184+
185+
await coursePage.configureExtensionsModal.toggleExtension('Extension 1');
186+
cards = coursePage.configureExtensionsModal.extensionCards.toArray();
187+
const disabledExtension1Card = cards.find((card) => card.name === 'Extension 1');
188+
assert.true(disabledExtension1Card.hasPill, 'Disabled extension still has pill when completed');
189+
assert.strictEqual(disabledExtension1Card.pillText, 'Completed', 'Disabled extension pill still shows "Completed"');
190+
});
138191
});

tests/pages/components/course-page/configure-extensions-modal.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { clickable, collection, text } from 'ember-cli-page-object';
1+
import { clickable, collection, isVisible, text } from 'ember-cli-page-object';
22
import { waitUntil } from '@ember/test-helpers';
33

44
export default {
@@ -11,6 +11,8 @@ export default {
1111
extensionCards: collection('[data-test-course-extension-card]', {
1212
name: text('[data-test-course-extension-name]'),
1313
clickOnToggleExtensionButton: clickable('[data-test-toggle-extension-button]'),
14+
hasPill: isVisible('[data-test-extension-progress-pill]'),
15+
pillText: text('[data-test-extension-progress-pill]'),
1416
}),
1517

1618
extensionIdeaCards: collection('[data-test-course-extension-idea-card]'),

0 commit comments

Comments
 (0)