Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,17 @@
}
</p>
}
@if (project.metadata.resources?.length > 0) {
<p>
<strong i18n>Resources:</strong>&nbsp;
@for (resource of project.metadata.resources; track resource.name; let last = $last) {
<a href="{{ resource.url }}" target="_blank" matTooltip="{{ resource.name }}">{{
resource.name
}}</a>
{{ last ? '' : ' | ' }}
}
</p>
}
<unit-tags [tags]="project.tags" />
</div>
@if (project.metadata.discourseCategoryURL) {
Expand Down Expand Up @@ -148,14 +159,21 @@
</div>
<div mat-dialog-actions class="flex flex-col sm:flex-row gap-2 sm:gap-4 !items-stretch" align="end">
<button mat-button cdkFocusInitial (click)="close()" i18n>Close</button>
@if (isTeacher && !isRunProject && project.wiseVersion !== 4) {
@if (
isTeacher &&
!isRunProject &&
project.wiseVersion !== 4 &&
project.metadata.unitType === 'Platform'
) {
<button mat-flat-button color="accent" (click)="runProject()">
<mat-icon>supervised_user_circle</mat-icon>&nbsp;<ng-container i18n
>Use with Class</ng-container
>
</button>
}
<button mat-flat-button color="primary" (click)="previewProject()">
<mat-icon>preview</mat-icon>&nbsp;<ng-container i18n>Preview</ng-container>
</button>
@if (project.metadata.unitType === 'Platform') {
<button mat-flat-button color="primary" (click)="previewProject()">
<mat-icon>preview</mat-icon>&nbsp;<ng-container i18n>Preview</ng-container>
</button>
}
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,16 @@ import { Project } from '../../../domain/project';
import { NGSSStandards } from '../ngssStandards';
import { ConfigService } from '../../../services/config.service';
import { ParentProject } from '../../../domain/parentProject';
import { MockProviders } from 'ng-mocks';
import { MockComponent, MockProviders } from 'ng-mocks';
import { By } from '@angular/platform-browser';
import { LibraryProjectMenuComponent } from '../library-project-menu/library-project-menu.component';

let component: LibraryProjectDetailsComponent;
let fixture: ComponentFixture<LibraryProjectDetailsComponent>;
describe('LibraryProjectDetailsComponent', () => {
let component: LibraryProjectDetailsComponent;
let fixture: ComponentFixture<LibraryProjectDetailsComponent>;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [MockComponent(LibraryProjectMenuComponent)],
imports: [LibraryProjectDetailsComponent],
providers: [
MockProviders(ConfigService, MatDialog, MatDialogRef, UserService),
Expand All @@ -30,11 +32,13 @@ describe('LibraryProjectDetailsComponent', () => {
grades: ['7'],
title: 'Photosynthesis & Cellular Respiration',
summary: 'A really great unit.',
unitType: 'Platform',
totalTime: '6-7 hours',
authors: [
{ id: 10, firstName: 'Spaceman', lastName: 'Spiff', username: 'SpacemanSpiff' },
{ id: 12, firstName: 'Captain', lastName: 'Napalm', username: 'CaptainNapalm' }
]
],
resources: [{ name: 'Resource 1', uri: 'http://example.com/resource1' }]
};
const ngssObject: any = {
disciplines: [
Expand Down Expand Up @@ -90,6 +94,11 @@ describe('LibraryProjectDetailsComponent', () => {
expect(compiled.textContent).toContain('by Spaceman Spiff, Captain Napalm');
});

it('should show project resources', () => {
const compiled = fixture.debugElement.nativeElement;
expect(compiled.textContent).toContain('Resource 1');
});

it('should show copied project info', () => {
component['project'].metadata.authors = [];
component['parentProject'] = new ParentProject({
Expand All @@ -103,4 +112,33 @@ describe('LibraryProjectDetailsComponent', () => {
const compiled = fixture.debugElement.nativeElement;
expect(compiled.textContent).toContain('is a copy of Photosynthesis');
});

it('should show use with class and preview buttons', () => {
component['isTeacher'] = true;
fixture.detectChanges();
expect(getButtonWithText('Use with Class')).toBeTruthy();
expect(getButtonWithText('Preview')).toBeTruthy();
});

isResourceUnitType_HideButtons();
});

function isResourceUnitType_HideButtons() {
describe('is not Resource unit type', () => {
beforeEach(() => {
component['project'].metadata.unitType = 'Resource';
fixture.detectChanges();
});

it('should hide buttons when unit type is Resource', () => {
expect(getButtonWithText('Use with Class')).toBeFalsy();
expect(getButtonWithText('Preview')).toBeFalsy();
});
});
}

function getButtonWithText(text: string) {
return fixture.debugElement
.queryAll(By.css('button'))
.find((el) => el.nativeElement.textContent.includes(text));
}
4 changes: 4 additions & 0 deletions src/app/teacher/authoring-tool.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ import { AddComponentComponent } from '../../assets/wise5/authoringTool/node/add
import { SideMenuComponent } from '../../assets/wise5/common/side-menu/side-menu.component';
import { MainMenuComponent } from '../../assets/wise5/common/main-menu/main-menu.component';
import { ChooseImportComponentComponent } from '../../assets/wise5/authoringTool/importComponent/choose-import-component/choose-import-component.component';
import { EditUnitResourcesComponent } from '../../assets/wise5/authoringTool/edit-unit-resources/edit-unit-resources.component';
import { EditUnitTypeComponent } from '../../assets/wise5/authoringTool/edit-unit-type/edit-unit-type.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -106,6 +108,8 @@ import { ChooseImportComponentComponent } from '../../assets/wise5/authoringTool
CreateBranchComponent,
EditBranchComponent,
EditNodeTitleComponent,
EditUnitResourcesComponent,
EditUnitTypeComponent,
MatBadgeModule,
MatChipsModule,
MatExpansionModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<ng-template #addButton let-addToTop="addToTop">
<button
mat-icon-button
color="primary"
matTooltip="Add a new resource"
i18n-matTooltip
matTooltipPosition="after"
(click)="addNewResource(addToTop)"
>
<mat-icon>add_circle</mat-icon>
</button>
</ng-template>
<div class="resource-descriptions notice-bg-bg">
<h5 class="flex flex-row items-center gap-1 !text-xl">
<span i18n>Resources</span>
<ng-container *ngTemplateOutlet="addButton; context: { addToTop: true }" />
<span class="flex-1"></span>
</h5>
<ul>
@for (
resource of resources;
track $index;
let resourceIndex = $index, first = $first, last = $last
) {
<li class="resource">
<mat-card appearance="outlined" class="resource-content">
<div class="flex flex-row flex-wrap gap-2">
<div class="text-secondary flex flex-col items-center">
<span class="mat-subtitle-1">{{ resourceIndex + 1 }}</span>
</div>
<div class="flex flex-col items-start gap-2 flex-1">
<mat-form-field class="resource-input form-field-no-hint" appearance="fill">
<mat-label i18n>Resource Name</mat-label>
<input
matInput
[(ngModel)]="resource.name"
(ngModelChange)="inputChanged.next($event)"
/>
</mat-form-field>
<mat-form-field class="resource-input form-field-no-hint" appearance="fill">
<mat-label i18n>Resource URL</mat-label>
<textarea
matInput
[(ngModel)]="resource.url"
(ngModelChange)="inputChanged.next($event)"
cdkTextareaAutosize
>
</textarea>
</mat-form-field>
</div>
<div class="flex flex-col items-center">
<button
mat-icon-button
i18n-matTooltip
matTooltip="Delete resource"
matTooltipPosition="before"
(click)="deleteResource(resourceIndex)"
>
<mat-icon>clear</mat-icon>
</button>
</div>
</div>
</mat-card>
</li>
}
</ul>
<div id="add-new-resource-bottom-button" [hidden]="resources.length === 0">
<ng-container *ngTemplateOutlet="addButton; context: { addToTop: false }" />
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@import 'style/abstracts/variables';

.resource-descriptions {
padding: 16px;
border-radius: $card-border-radius;
}

h5 {
margin-top: 0;
}

ul {
margin: 16px 0 0 0;
padding: 0 0 16px;
}

li {
list-style-type: none;
}

.resource {
position: relative;
}

.resource-content {
width: 100%;
padding: 8px;
margin-bottom: 8px;
}

.resource-input {
width: 100%;
}

.mat-subtitle-1 {
margin: 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EditUnitResourcesComponent } from './edit-unit-resources.component';
import { MockProvider } from 'ng-mocks';
import { TeacherProjectService } from '../../services/teacherProjectService';
import { By } from '@angular/platform-browser';

let component: EditUnitResourcesComponent;
let fixture: ComponentFixture<EditUnitResourcesComponent>;
describe('EditUnitResourcesComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [EditUnitResourcesComponent],
providers: [MockProvider(TeacherProjectService)]
}).compileComponents();

fixture = TestBed.createComponent(EditUnitResourcesComponent);
component = fixture.componentInstance;
component.resources = [
{ name: 'Resource 1', url: 'http://example.com/resource1' },
{ name: 'Resource 2', url: 'http://example.com/resource2' }
];
fixture.detectChanges();
});

it('should show the correct number of resources', () => {
const resourceElements = fixture.debugElement.queryAll(By.css('input'));
expect(resourceElements.length).toBe(2);
expect(resourceElements[0].nativeElement.value).toContain('Resource 1');
expect(resourceElements[1].nativeElement.value).toContain('Resource 2');
});

clickTopAddButton_addNewResourceAtTheBeginning();
clickBottomTopButton_addNewResourceAtTheEnd();
});

function clickTopAddButton_addNewResourceAtTheBeginning() {
describe('Clicking on the top Add Resource button', () => {
let initialLength = 0;
beforeEach(() => {
initialLength = component.resources.length;
fixture.debugElement.queryAll(By.css('button'))[0].nativeElement.click();
fixture.detectChanges();
});
it('should add a new resource to the beginning of the list', () => {
expect(component.resources.length).toBe(initialLength + 1);
expect(component.resources[0].name).toEqual('');
expect(component.resources[0].url).toEqual('');
});
});
}

function clickBottomTopButton_addNewResourceAtTheEnd() {
describe('Clicking on the bottom Add Resource button', () => {
let initialLength = 0;
beforeEach(() => {
initialLength = component.resources.length;
const allButtons = fixture.debugElement.queryAll(By.css('button'));
allButtons[allButtons.length - 1].nativeElement.click();
fixture.detectChanges();
});
it('should add a new resource to the end of the list', () => {
expect(component.resources.length).toBe(initialLength + 1);
expect(component.resources.at(-1).name).toEqual('');
expect(component.resources.at(-1).url).toEqual('');
});
});
}
Loading
Loading