Skip to content

Commit

Permalink
feat(Authoring): Add delete button to all steps (#1633)
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffreykwan authored Feb 20, 2024
1 parent 0ae45e3 commit e691cdb
Show file tree
Hide file tree
Showing 12 changed files with 205 additions and 82 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<node-icon [nodeId]="nodeId" size="18"></node-icon>&nbsp;
<span *ngIf="showPosition">{{ getNodePosition(nodeId) }}:&nbsp;</span>{{ getNodeTitle(nodeId) }}
<span *ngIf="showPosition" class="step-number">{{ getNodePosition(nodeId) }}: </span>
<span class="step-title">{{ getNodeTitle(nodeId) }}</span>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ComponentHarness } from '@angular/cdk/testing';

export class NodeIconAndTitleHarness extends ComponentHarness {
static hostSelector = 'node-icon-and-title';

getStepPosition = this.locatorForOptional('.step-number');
getStepTitle = this.locatorFor('.step-title');

async getPositionAndTitle(): Promise<string> {
const position = await (await this.getStepPosition())?.text();
const title = await (await this.getStepTitle()).text();
return position == null ? title : `${position} ${title}`;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { MatIconModule } from '@angular/material/icon';
import { ProjectAuthoringStepComponent } from '../project-authoring-step/project-authoring-step.component';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ProjectAuthoringLessonHarness } from './project-authoring-lesson.harness';
import { DeleteNodeService } from '../../services/deleteNodeService';
import { RouterTestingModule } from '@angular/router/testing';

let component: ProjectAuthoringLessonComponent;
let fixture: ComponentFixture<ProjectAuthoringLessonComponent>;
Expand All @@ -39,10 +41,12 @@ describe('ProjectAuthoringLessonComponent', () => {
MatCheckboxModule,
MatDialogModule,
MatIconModule,
RouterTestingModule,
StudentTeacherCommonServicesModule
],
providers: [
ClassroomStatusService,
DeleteNodeService,
TeacherDataService,
TeacherProjectService,
TeacherWebSocketService
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,72 @@
<div
id="{{ step.id }}"
fxLayoutAlign="start center"
class="pointer stepHeader projectItem"
[ngClass]="{ branchPathStepHeader: isNodeInAnyBranchPath(step.id) }"
fxLayoutGap="10px"
class="step pointer"
[ngClass]="{ 'branch-path-step': isNodeInAnyBranchPath(step.id) }"
[ngStyle]="{ 'background-color': getStepBackgroundColor(step.id) }"
(click)="setCurrentNode(step.id)"
>
<mat-checkbox
color="primary"
(change)="selectNode($event.checked)"
(click)="$event.stopPropagation()"
[disabled]="nodeTypeSelected() === 'lesson'"
aria-label="Select step"
i18n-aria-label
>
<node-icon-and-title [nodeId]="step.id" [showPosition]="showPosition"></node-icon-and-title>
</mat-checkbox>
<div fxLayoutAlign="start center" fxLayoutGap="10px">
<mat-icon
*ngIf="isBranchPoint(step.id)"
class="rotate-180"
(click)="branchIconClicked(step.id); $event.stopPropagation()"
matTooltip="Branch point with {{ getNumberOfBranchPaths(step.id) }} paths based on {{
getBranchCriteriaDescription(step.id)
}}"
matTooltipPosition="right"
i18n-matTooltip
>call_split</mat-icon
>
<mat-icon
*ngIf="nodeHasConstraint(step.id)"
(click)="constraintIconClicked(step.id); $event.stopPropagation()"
matTooltip="{{ getNumberOfConstraintsOnNode(step.id) }} Constraint(s) {{
getConstraintDescriptions(step.id)
}}"
matTooltipPosition="right"
i18n-matTooltip
>block</mat-icon
>
<mat-icon
*ngIf="nodeHasRubric(step.id)"
matTooltip="Has Rubric"
matTooltipPosition="right"
i18n-matTooltip
>message</mat-icon
>
</div>
<div
class="projectItemTitleDiv"
fxLayoutAlign="start center"
fxLayoutGap="10px"
(click)="setCurrentNode(step.id)"
class="step-click-to-enter-div"
matTooltip="Click to enter step"
matTooltipPosition="above"
i18n-matTooltip
>
<node-icon-and-title [nodeId]="step.id" [showPosition]="showPosition"></node-icon-and-title>
<p fxLayoutAlign="start center" fxLayoutGap="10px">
<mat-icon
*ngIf="isBranchPoint(step.id)"
class="rotate-180"
(click)="branchIconClicked(step.id); $event.stopPropagation()"
matTooltip="Branch point with {{ getNumberOfBranchPaths(step.id) }} paths based on {{
getBranchCriteriaDescription(step.id)
}}"
matTooltipPosition="right"
i18n-matTooltip
>call_split</mat-icon
>
<mat-icon
*ngIf="nodeHasConstraint(step.id)"
(click)="constraintIconClicked(step.id); $event.stopPropagation()"
matTooltip="{{ getNumberOfConstraintsOnNode(step.id) }} Constraint(s) {{
getConstraintDescriptions(step.id)
}}"
matTooltipPosition="right"
i18n-matTooltip
>block</mat-icon
>
<mat-icon
*ngIf="nodeHasRubric(step.id)"
matTooltip="Has Rubric"
matTooltipPosition="right"
fxFlex
></div>
<div class="dynamic-step-buttons">
<div fxLayoutAlign="start center">
<button
mat-icon-button
class="delete-button"
(click)="delete($event)"
color="primary"
matTooltip="Delete step"
matTooltipPosition="above"
i18n-matTooltip
>message</mat-icon
>
</p>
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
.stepHeader {
margin-left: 30px !important;
.step {
height: 50px;
padding: 4px;
margin: 4px 30px;
border: 2px solid #dddddd;
border-radius: 6px;
position: relative;
}

.branchPathStepHeader {
.step:hover {
background-color: #add8e6 !important;
}

.branch-path-step {
margin-left: 55px !important;
}

.pointer {
cursor: pointer;
}

.projectItem:hover {
background-color: #add8e6;
.dynamic-step-buttons {
display: none;
}

.projectItemTitleDiv:hover {
background-color: #add8e6;
.step:hover .dynamic-step-buttons {
display: block;
}

.projectItemTitleDiv {
width: 100%;
font-weight: initial;
.step-click-to-enter-div {
flex-grow: 1;
align-self: stretch;
}

.rotate-180 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import { NodeIconAndTitleComponent } from '../choose-node-location/node-icon-and
import { NodeIconComponent } from '../../vle/node-icon/node-icon.component';
import { FormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { DeleteNodeService } from '../../services/deleteNodeService';
import { RouterTestingModule } from '@angular/router/testing';

const nodeId1 = 'nodeId1';
const node = { id: nodeId1 };
Expand All @@ -29,10 +31,12 @@ describe('ProjectAuthoringStepComponent', () => {
MatCheckboxModule,
MatDialogModule,
MatIconModule,
RouterTestingModule,
StudentTeacherCommonServicesModule
],
providers: [
ClassroomStatusService,
DeleteNodeService,
TeacherDataService,
TeacherProjectService,
TeacherWebSocketService
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TeacherDataService } from '../../services/teacherDataService';
import { Router } from '@angular/router';
import { SelectNodeEvent } from '../domain/select-node-event';
import { NodeTypeSelected } from '../domain/node-type-selected';
import { DeleteNodeService } from '../../services/deleteNodeService';

@Component({
selector: 'project-authoring-step',
Expand All @@ -19,6 +20,7 @@ export class ProjectAuthoringStepComponent {

constructor(
private dataService: TeacherDataService,
private deleteNodeService: DeleteNodeService,
private projectService: TeacherProjectService,
private router: Router
) {}
Expand Down Expand Up @@ -90,4 +92,17 @@ export class ProjectAuthoringStepComponent {
this.dataService.setCurrentNodeByNodeId(nodeId);
this.router.navigate([`/teacher/edit/unit/${this.projectId}/node/${nodeId}/advanced/path`]);
}

protected delete(event: Event): void {
event.stopPropagation();
if (confirm($localize`Are you sure you want to delete this step?`)) {
this.deleteNodeService.deleteNode(this.step.id);
this.saveAndRefreshProject();
}
}

private saveAndRefreshProject(): void {
this.projectService.saveProject();
this.projectService.refreshProject();
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
import { ComponentHarness } from '@angular/cdk/testing';
import { BaseHarnessFilters, ComponentHarness, HarnessPredicate } from '@angular/cdk/testing';
import { NodeIconAndTitleHarness } from '../choose-node-location/node-icon-and-title/node-icon-and-title.harness';
import { MatButtonHarness } from '@angular/material/button/testing';

interface ProjectAuthoringStepHarnessFilters extends BaseHarnessFilters {
title?: string | RegExp;
}

export class ProjectAuthoringStepHarness extends ComponentHarness {
static hostSelector = 'project-authoring-step';

getStepTitleElement = this.locatorFor(NodeIconAndTitleHarness);
getDeleteButton = this.locatorFor(MatButtonHarness.with({ selector: '.delete-button' }));

static with(
options: ProjectAuthoringStepHarnessFilters
): HarnessPredicate<ProjectAuthoringStepHarness> {
return new HarnessPredicate(ProjectAuthoringStepHarness, options).addOption(
'title',
options.title,
async (harness, title) => {
return HarnessPredicate.stringMatches(harness.getStepTitle(), title);
}
);
}

async getStepTitle(): Promise<string> {
const stepTitleElement = await this.getStepTitleElement();
return await stepTitleElement.getPositionAndTitle();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ describe('ProjectAuthoringComponent', () => {

collapseAllButtonClicked();
expandAllButtonClicked();
deleteSpecificStep();
});

function collapseAllButtonClicked() {
Expand Down Expand Up @@ -137,3 +138,15 @@ function expandAllButtonClicked() {
});
});
}

function deleteSpecificStep() {
describe('delete step button on a specific step is clicked', () => {
it('deletes the step', async () => {
expect((await harness.getSteps()).length).toEqual(49);
spyOn(window, 'confirm').and.returnValue(true);
const step = await harness.getStep('1.1: HTML Step');
await (await step.getDeleteButton()).click();
expect((await harness.getSteps()).length).toEqual(48);
});
});
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { ComponentHarness } from '@angular/cdk/testing';
import { MatButtonHarness } from '@angular/material/button/testing';
import { ProjectAuthoringLessonHarness } from '../project-authoring-lesson/project-authoring-lesson.harness';
import { ProjectAuthoringStepHarness } from '../project-authoring-step/project-authoring-step.harness';

export class ProjectAuthoringHarness extends ComponentHarness {
static hostSelector = 'project-authoring';
getExpandAllButton = this.locatorFor(MatButtonHarness.with({ text: '+ Expand All' }));
getCollapseAllButton = this.locatorFor(MatButtonHarness.with({ text: '- Collapse All' }));
getLessons = this.locatorForAll(ProjectAuthoringLessonHarness);
getSteps = this.locatorForAll(ProjectAuthoringStepHarness);

getStep(title: string): Promise<ProjectAuthoringStepHarness> {
return this.locatorForOptional(ProjectAuthoringStepHarness.with({ title: title }))();
}
}
4 changes: 3 additions & 1 deletion src/assets/wise5/services/projectService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ export class ProjectService {
this.inactiveStepNodes = [];
this.inactiveGroupNodes = [];
this.groupNodes = [];
this.idToNode = {};
Object.keys(this.idToNode).forEach((key) => {
delete this.idToNode[key];
});
this.metadata = {};
this.rootNode = null;
this.idToOrder = {};
Expand Down
Loading

0 comments on commit e691cdb

Please sign in to comment.