-
Notifications
You must be signed in to change notification settings - Fork 19
[ENG-8504] Show Osf introduction video and Collections,Institutions, Registries, Preprints url banners if user have not created any project for home (/dashboard) tab #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
fa646b2
deb6fda
817fcde
4ea197b
8b08eb2
9518a69
ae3d58c
78d9a3f
5b507ee
b4e4b36
d11d726
4a41ac8
cdc4148
a2bf142
7026035
78b2b23
90957d3
d191424
dc756f2
3da021a
33235f5
e5bdb8f
928c19f
c8c4e9b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,61 +1,141 @@ | ||
<section class="home-container xl:mt-6"> | ||
<osf-sub-header | ||
[showButton]="true" | ||
[title]="'home.loggedIn.dashboard.title' | translate" | ||
[icon]="'fas fa-home'" | ||
[buttonLabel]="'home.loggedIn.dashboard.createProject' | translate" | ||
(buttonClick)="createProject()" | ||
/> | ||
|
||
<div class="quick-search-container py-4 px-3 md:px-4"> | ||
<p class="text-center mb-4 xl:mb-6"> | ||
{{ 'home.loggedIn.dashboard.quickSearch.goTo' | translate }} | ||
<a routerLink="/my-projects"> | ||
{{ 'home.loggedIn.dashboard.quickSearch.myProjects' | translate }} | ||
<section class="home-container xl:mt-6" [class.medium]="isMedium()"> | ||
@if (areProjectsLoading()) { | ||
<osf-loading-spinner /> | ||
} @else { | ||
@if (existsProjects()) { | ||
<osf-sub-header | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The html for the else if and else conditions if fairly large. I will let you make the decision and there's a fine line between leaving it as 1 component or splitting it into two components. What do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
[showButton]="true" | ||
[title]="'home.loggedIn.dashboard.title' | translate" | ||
[icon]="'home'" | ||
[buttonLabel]="'home.loggedIn.dashboard.createProject' | translate" | ||
(buttonClick)="createProject()" | ||
/> | ||
<div> | ||
<div class="quick-search-container py-4 px-3 md:px-4"> | ||
<p class="text-center mb-4 xl:mb-6"> | ||
{{ 'home.loggedIn.dashboard.quickSearch.goTo' | translate }} | ||
<a routerLink="/my-projects"> | ||
{{ 'home.loggedIn.dashboard.quickSearch.myProjects' | translate }} | ||
</a> | ||
{{ 'home.loggedIn.dashboard.quickSearch.toOrganize' | translate }} | ||
<a routerLink="/search"> | ||
{{ 'home.loggedIn.dashboard.quickSearch.search' | translate }} | ||
</a> | ||
{{ 'home.loggedIn.dashboard.quickSearch.osf' | translate }} | ||
</p> | ||
|
||
<osf-my-projects-table | ||
[items]="filteredProjects()" | ||
[tableParams]="tableParams()" | ||
[searchControl]="searchControl" | ||
[sortColumn]="sortColumn()" | ||
[sortOrder]="sortOrder()" | ||
[isLoading]="areProjectsLoading()" | ||
[searchPlaceholder]="'home.loggedIn.dashboard.quickSearch.searchPlaceholder' | translate" | ||
(pageChange)="onPageChange($event)" | ||
(sort)="onSort($event)" | ||
(itemClick)="navigateToProject($event)" | ||
/> | ||
</div> | ||
|
||
<div class="public-projects-container flex align-items-center flex-row pt-6 pb-4 px-3 md:px-4 xl:py-6"> | ||
<osf-icon class="mr-2" iconClass="fas fa-2xl fa-magnifying-glass"></osf-icon> | ||
<h1>{{ 'home.loggedIn.publicProjects.title' | translate }}</h1> | ||
</div> | ||
|
||
<div | ||
class="latest-research-container flex flex-column gap-4 py-6 px-3 md:px-4 xl:flex-row xl:justify-content-between" | ||
> | ||
<div> | ||
<h1>{{ 'home.loggedIn.latestResearch.title' | translate }}</h1> | ||
<p class="m-t-12">{{ 'home.loggedIn.latestResearch.subtitle' | translate }}</p> | ||
</div> | ||
|
||
<p-button | ||
routerLink="/preprints" | ||
[label]="'home.loggedIn.latestResearch.button' | translate" | ||
severity="success" | ||
/> | ||
</div> | ||
|
||
<div class="hosting-container flex flex-column gap-4 py-6 px-3 md:px-4 xl:flex-row xl:justify-content-between"> | ||
<div class="text-container"> | ||
<h1>{{ 'home.loggedIn.hosting.title' | translate }}</h1> | ||
<p class="m-t-12">{{ 'home.loggedIn.hosting.subtitle' | translate }}</p> | ||
</div> | ||
|
||
<p-button routerLink="/meetings" [label]="'home.loggedIn.hosting.button' | translate" severity="success" /> | ||
</div> | ||
</div> | ||
} @else { | ||
<osf-sub-header | ||
[showButton]="true" | ||
[title]="'home.loggedIn.dashboard.welcome' | translate" | ||
[icon]="'home'" | ||
[buttonLabel]="'home.loggedIn.dashboard.createProject' | translate" | ||
(buttonClick)="createProject()" | ||
/> | ||
<div class="flex items-center justify-center min-h-screen bg-white pt-4"> | ||
<div class="text-center max-w-2xl px-6 w-full"> | ||
<p class="mb-4">{{ 'home.loggedIn.dashboard.noCreatedProject' | translate }}</p> | ||
|
||
<p class="mb-6">{{ 'home.loggedIn.dashboard.watchVideoBelow' | translate }}</p> | ||
|
||
<div class="mb-6 flex flex-column align-items-center w-full"> | ||
<iframe | ||
width="560" | ||
height="315" | ||
src="https://www.youtube.com/embed/X07mBq2tnMg" | ||
title="Introduction to OSF" | ||
frameborder="0" | ||
allowfullscreen | ||
class="rounded-xl shadow-md" | ||
></iframe> | ||
</div> | ||
|
||
<div class="flex justify-content-center mt-4 mb-4"> | ||
<p-button | ||
[label]="'home.loggedIn.dashboard.getStartedHelp' | translate" | ||
severity="secondary" | ||
(onClick)="openInfoLink()" | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
} | ||
<div class="flex flex-column align-items-left w-full mt-4 ml-4 mb-4"> | ||
<a | ||
href="https://www.cos.io/products/osf-collections" | ||
target="_blank" | ||
rel="noopener noreferrer" | ||
data-test-products-collections | ||
> | ||
<img | ||
src="assets/images/dashboard/products/osf-collections.png" | ||
[alt]="'home.loggedIn.dashboard.images.osfCollectionsImageAltText' | translate" | ||
/> | ||
</a> | ||
{{ 'home.loggedIn.dashboard.quickSearch.toOrganize' | translate }} | ||
<a routerLink="/search"> | ||
{{ 'home.loggedIn.dashboard.quickSearch.search' | translate }} | ||
|
||
<a routerLink="/institutions"> | ||
<img | ||
src="assets/images/dashboard/products/osf-institutions.png" | ||
[alt]="'home.loggedIn.dashboard.images.osfInstitutionsImageAltText' | translate" | ||
/> | ||
</a> | ||
{{ 'home.loggedIn.dashboard.quickSearch.osf' | translate }} | ||
</p> | ||
|
||
<osf-my-projects-table | ||
[items]="filteredProjects()" | ||
[tableParams]="tableParams()" | ||
[searchControl]="searchControl" | ||
[sortColumn]="sortColumn()" | ||
[sortOrder]="sortOrder()" | ||
[isLoading]="areProjectsLoading()" | ||
[searchPlaceholder]="'home.loggedIn.dashboard.quickSearch.searchPlaceholder' | translate" | ||
(pageChange)="onPageChange($event)" | ||
(sort)="onSort($event)" | ||
(itemClick)="navigateToProject($event)" | ||
/> | ||
</div> | ||
|
||
<div class="public-projects-container flex align-items-center flex-row pt-6 pb-4 px-3 md:px-4 xl:py-6"> | ||
<osf-icon class="mr-2" iconClass="fas fa-2xl fa-magnifying-glass"></osf-icon> | ||
<h1>{{ 'home.loggedIn.publicProjects.title' | translate }}</h1> | ||
</div> | ||
|
||
<div | ||
class="latest-research-container flex flex-column gap-4 py-6 px-3 md:px-4 xl:flex-row xl:justify-content-between" | ||
> | ||
<div> | ||
<h1>{{ 'home.loggedIn.latestResearch.title' | translate }}</h1> | ||
<p class="m-t-12">{{ 'home.loggedIn.latestResearch.subtitle' | translate }}</p> | ||
</div> | ||
|
||
<p-button routerLink="/preprints" [label]="'home.loggedIn.latestResearch.button' | translate" severity="success" /> | ||
</div> | ||
<a routerLink="/registries"> | ||
<img | ||
src="assets/images/dashboard/products/osf-registries.png" | ||
[alt]="'home.loggedIn.dashboard.images.osfRegistriesImageAltTest' | translate" | ||
/> | ||
</a> | ||
|
||
<div class="hosting-container flex flex-column gap-4 py-6 px-3 md:px-4 xl:flex-row xl:justify-content-between"> | ||
<div class="text-container"> | ||
<h1>{{ 'home.loggedIn.hosting.title' | translate }}</h1> | ||
<p class="m-t-12">{{ 'home.loggedIn.hosting.subtitle' | translate }}</p> | ||
<a routerLink="/preprints"> | ||
<img | ||
src="assets/images/dashboard/products/osf-preprints.png" | ||
[alt]="'home.loggedIn.dashboard.images.osfPreprintsImageAltTest' | translate" | ||
/> | ||
</a> | ||
</div> | ||
|
||
<p-button routerLink="/meetings" [label]="'home.loggedIn.hosting.button' | translate" severity="success" /> | ||
</div> | ||
} | ||
</section> |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should any text (translations string) or links be verified after the spinners are finished loading? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have added test to verify product images |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,133 @@ | ||
import { Store } from '@ngxs/store'; | ||
|
||
import { MockComponents } from 'ng-mocks'; | ||
|
||
import { signal, WritableSignal } from '@angular/core'; | ||
import { ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { By } from '@angular/platform-browser'; | ||
|
||
import { LoadingSpinnerComponent, MyProjectsTableComponent, SubHeaderComponent } from '@shared/components'; | ||
import { MyResourcesSelectors } from '@shared/stores'; | ||
|
||
import { DashboardComponent } from './dashboard.component'; | ||
|
||
describe.skip('DashboardComponent', () => { | ||
import { getProjectsMockForComponent } from '@testing/data/dashboard/dasboard.data'; | ||
import { OSFTestingStoreModule } from '@testing/osf.testing.module'; | ||
|
||
describe('DashboardComponent', () => { | ||
let component: DashboardComponent; | ||
let fixture: ComponentFixture<DashboardComponent>; | ||
|
||
let projectsSignal: WritableSignal<any[]>; | ||
let totalProjectsSignal: WritableSignal<number>; | ||
let areProjectsLoadingSignal: WritableSignal<boolean>; | ||
|
||
beforeEach(async () => { | ||
projectsSignal = signal(getProjectsMockForComponent()); | ||
totalProjectsSignal = signal(getProjectsMockForComponent().length); | ||
areProjectsLoadingSignal = signal(false); | ||
|
||
await TestBed.configureTestingModule({ | ||
imports: [DashboardComponent], | ||
imports: [ | ||
DashboardComponent, | ||
OSFTestingStoreModule, | ||
...MockComponents(SubHeaderComponent, MyProjectsTableComponent, LoadingSpinnerComponent), | ||
], | ||
providers: [ | ||
{ | ||
provide: Store, | ||
useValue: { | ||
selectSignal: (selector: any) => { | ||
if (selector === MyResourcesSelectors.getProjects) return projectsSignal; | ||
if (selector === MyResourcesSelectors.getTotalProjects) return totalProjectsSignal; | ||
if (selector === MyResourcesSelectors.getProjectsLoading) return areProjectsLoadingSignal; | ||
return signal(null); | ||
}, | ||
dispatch: jest.fn(), | ||
}, | ||
}, | ||
], | ||
}).compileComponents(); | ||
|
||
fixture = TestBed.createComponent(DashboardComponent); | ||
component = fixture.componentInstance; | ||
}); | ||
|
||
it('should show loading s pinner when projects are loading', () => { | ||
areProjectsLoadingSignal.set(true); | ||
fixture.detectChanges(); | ||
|
||
const spinner = fixture.debugElement.query(By.directive(LoadingSpinnerComponent)); | ||
expect(spinner).toBeTruthy(); | ||
}); | ||
|
||
it('should render projects table when projects exist', () => { | ||
projectsSignal.set(getProjectsMockForComponent()); | ||
totalProjectsSignal.set(getProjectsMockForComponent().length); | ||
areProjectsLoadingSignal.set(false); | ||
fixture.detectChanges(); | ||
|
||
const table = fixture.debugElement.query(By.directive(MyProjectsTableComponent)); | ||
expect(table).toBeTruthy(); | ||
}); | ||
|
||
it('should render welcome video when no projects exist', () => { | ||
projectsSignal.set([]); | ||
totalProjectsSignal.set(0); | ||
areProjectsLoadingSignal.set(false); | ||
fixture.detectChanges(); | ||
const iframe = fixture.debugElement.query(By.css('iframe')); | ||
expect(iframe).toBeTruthy(); | ||
expect(iframe.nativeElement.src).toContain('youtube.com'); | ||
}); | ||
|
||
it('should create', () => { | ||
expect(component).toBeTruthy(); | ||
it('should render welcome screen when no projects exist', () => { | ||
projectsSignal.set([]); | ||
totalProjectsSignal.set(0); | ||
areProjectsLoadingSignal.set(false); | ||
fixture.detectChanges(); | ||
|
||
const welcomeText = fixture.debugElement.nativeElement.textContent; | ||
expect(welcomeText).toContain('home.loggedIn.dashboard.noCreatedProject'); | ||
}); | ||
|
||
it('should open OSF help link in new tab when openInfoLink is called', () => { | ||
const spy = jest.spyOn(window, 'open').mockImplementation(() => null); | ||
component.openInfoLink(); | ||
expect(spy).toHaveBeenCalledWith('https://help.osf.io/', '_blank'); | ||
}); | ||
|
||
it('should render product images after loading spinner disappears', () => { | ||
areProjectsLoadingSignal.set(true); | ||
fixture.detectChanges(); | ||
|
||
let productImages = fixture.debugElement | ||
.queryAll(By.css('img')) | ||
.filter((img) => img.nativeElement.getAttribute('src')?.includes('assets/images/dashboard/products/')); | ||
|
||
expect(productImages.length).toBe(0); | ||
|
||
const spinner = fixture.debugElement.query(By.css('osf-loading-spinner')); | ||
expect(spinner).toBeTruthy(); | ||
|
||
areProjectsLoadingSignal.set(false); | ||
fixture.detectChanges(); | ||
|
||
productImages = fixture.debugElement | ||
.queryAll(By.css('img')) | ||
.filter((img) => img.nativeElement.getAttribute('src')?.includes('assets/images/dashboard/products/')); | ||
|
||
expect(productImages.length).toBe(4); | ||
|
||
const sources = productImages.map((img) => img.nativeElement.getAttribute('src')); | ||
|
||
expect(sources).toEqual( | ||
expect.arrayContaining([ | ||
'assets/images/dashboard/products/osf-collections.png', | ||
'assets/images/dashboard/products/osf-institutions.png', | ||
'assets/images/dashboard/products/osf-registries.png', | ||
'assets/images/dashboard/products/osf-preprints.png', | ||
]) | ||
); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this @else could likely be a @esle if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if workflow goes to
else
it is needed to render highlighted codeif we use
@if (isProjectsLoading())
->@else if (existsProjects() || !!searchControl.value?.length)
->else
it will be needed to duplicate the code for
else if
andelse