Skip to content
Permalink
Browse files
feat(overview): add overview and project tile components (DEV-984) (#777
)

* feat(overview): add overview and project tile components

* update css

* feat(overview): add additional css and click events

* feat(overview): add view for unknown user, add create new project button for sysadmins, add logic to redirect user to project dashboard if only member of one project

* feat(project): add sidenav item to go to the projects overview

* test(overview, project-tile): fix test for overview. fix and add tests for project-tile

* test(overview): add tests for overview component

* refactor(overview): simplify logic to use two arrays instead of three

* fix(users-list): get shortcode from grandchild route in the case user is in the beta view

* chore(project): adjust comment
  • Loading branch information
mdelez committed Jul 27, 2022
1 parent 654d2e6 commit a64359b33f7c5e73efb2c3e602ebeb3ade8cc02e
Show file tree
Hide file tree
Showing 20 changed files with 981 additions and 27 deletions.
@@ -24,6 +24,7 @@ import { SystemComponent } from './system/system.component';
import { UsersComponent } from './system/users/users.component';
// user
import { DashboardComponent } from './user/dashboard/dashboard.component';
import { OverviewComponent } from './user/overview/overview.component';
import { UserComponent } from './user/user.component';
// search results and resource viewer
import { ResourceComponent } from './workspace/resource/resource.component';
@@ -42,6 +43,10 @@ const routes: Routes = [
path: 'login',
component: LoginFormComponent
},
{
path: 'overview',
component: OverviewComponent
},
{
path: 'dashboard',
component: DashboardComponent,
@@ -165,6 +165,8 @@ import { OntologyClassesComponent } from './project/beta/ontology-classes/ontolo
import { OntologyClassItemComponent } from './project/beta/ontology-classes/ontology-class-item/ontology-class-item.component';
import { OntologyClassInstanceComponent } from './project/beta/ontology-classes/ontology-class-instance/ontology-class-instance.component';
import { SettingsComponent } from './project/beta/settings/settings.component';
import { OverviewComponent } from './user/overview/overview.component';
import { ProjectTileComponent } from './system/project-tile/project-tile.component';

// translate: AoT requires an exported function for factories
export function httpLoaderFactory(httpClient: HttpClient) {
@@ -316,7 +318,9 @@ export function httpLoaderFactory(httpClient: HttpClient) {
OntologyClassesComponent,
OntologyClassItemComponent,
OntologyClassInstanceComponent,
SettingsComponent
SettingsComponent,
OverviewComponent,
ProjectTileComponent,
],
imports: [
AngularSplitModule.forRoot(),
@@ -1,7 +1,7 @@
import { AfterViewInit, Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { ApiResponseData, ApiResponseError, KnoraApiConnection, LoginResponse } from '@dasch-swiss/dsp-js';
import { ApiResponseData, ApiResponseError, KnoraApiConnection, LoginResponse, UserResponse } from '@dasch-swiss/dsp-js';
import { DspApiConnectionToken } from '../../declarations/dsp-api-tokens';
import { ErrorHandlerService } from '../../services/error-handler.service';
import { AuthenticationService } from '../../services/authentication.service';
@@ -158,9 +158,26 @@ export class LoginFormComponent implements OnInit, AfterViewInit {
this.session = this._session.getSession();

this._componentCommsService.emit(new EmitEvent(Events.loginSuccess, true));

// if user hit a page that requires to be logged in, they will have a returnUrl in the url
this.returnUrl = this._route.snapshot.queryParams['returnUrl'];
if (this.returnUrl) {
this._router.navigate([this.returnUrl]);
} else if (this._route.snapshot.url.length && this._route.snapshot.url[0].path === 'login') { // if user is on /login
const username = this.session.user.name;
this._dspApiConnection.admin.usersEndpoint.getUserByUsername(username).subscribe(
(userResponse: ApiResponseData<UserResponse>) => {
// if user is only a member of one project, redirect them to that projects dashboard
if(userResponse.body.user.projects.length === 1) {
this._router.navigateByUrl('/refresh', { skipLocationChange: true }).then(
() => this._router.navigate(['/beta/project/' + userResponse.body.user.projects[0].shortcode])
);
} else { // if user is a member of multiple projects, redirect them to the overview
this._router.navigateByUrl('/refresh', { skipLocationChange: true }).then(
() => this._router.navigate(['/overview'])
);
}
});
} else {
window.location.reload();
}
@@ -417,8 +417,8 @@ export class ProjectFormComponent implements OnInit {
this.loading = false;
this.closeDialog.emit();
// redirect to (new) project page
this._router.navigateByUrl('/project', { skipLocationChange: true }).then(() =>
this._router.navigate(['/project/' + this.form.controls['shortcode'].value])
this._router.navigateByUrl('/beta/project', { skipLocationChange: true }).then(() =>
this._router.navigate(['/beta/project/' + this.form.controls['shortcode'].value])
);
},
(error: ApiResponseError) => {
@@ -31,7 +31,12 @@ <h1 class="mat-headline">
</mat-list-item>
<!-- Maybe we can have a project selector here (similar to the github dashboard page) -->
<mat-divider></mat-divider>

<mat-list-item>
<span class="link section-label" (click)="goToOverview()">
<p>Go to projects overview</p>
</span>
</mat-list-item>
<mat-divider></mat-divider>
<!-- Ontology Section -->
<mat-list-item class="section-title">
<span class="link section-label" (click)="open('ontology')">
@@ -50,7 +55,8 @@ <h2 class="mat-title">Data Models</h2>
<mat-expansion-panel [expanded]="true">
<mat-expansion-panel-header>
<div class="sidenav-panel-header" (click)="$event.stopPropagation();">
<mat-panel-title class="mat-subheading-2" (click)="projectAdmin ? open('ontology', onto.id) : null">
<mat-panel-title class="mat-subheading-2"
(click)="projectAdmin ? open('ontology', onto.id) : null">
{{onto.label}}
</mat-panel-title>
<mat-panel-description>
@@ -69,7 +75,8 @@ <h2 class="mat-title">Data Models</h2>
</button>
</mat-list-item> -->
<mat-list>
<app-ontology-classes [resClasses]="onto.getAllClassDefinitions()" [projectMember]="projectMember">
<app-ontology-classes [resClasses]="onto.getAllClassDefinitions()"
[projectMember]="projectMember">
</app-ontology-classes>
</mat-list>
</mat-expansion-panel>
@@ -86,7 +93,7 @@ <h2 class="mat-title">Data Models</h2>
<h2 class="mat-title">Lists</h2>
</span>
<span class="fill-remaining-space"></span>
<button mat-icon-button class="hover-only"(click)="open('add-list')">
<button mat-icon-button class="hover-only" (click)="open('add-list')">
<mat-icon>add</mat-icon>
</button>
</mat-list-item>
@@ -105,7 +112,7 @@ <h2 class="mat-title">Members</h2>

<!-- Project permissions ??? will it ever come? -->

<div class="sidenav-footer" *ngIf="projectAdmin" >
<div class="sidenav-footer" *ngIf="projectAdmin">
<mat-list-item class="section-title">
<span class="link section-label" (click)="open('settings')">
<mat-icon class="sidenav-prefix-icon">settings</mat-icon>
@@ -129,4 +136,4 @@ <h2 class="mat-title">Settings</h2>
<div class="content large middle">
<app-status *ngIf="error" [status]="404"></app-status>
</div>
</ng-template>
</ng-template>
@@ -222,6 +222,13 @@ export class ProjectComponent implements OnInit {
}
}

/**
* go to overview page
*/
goToOverview() {
this._router.navigate(['/overview'], { relativeTo: this._route });
}

/**
* checks if the shortcode is valid: hexadecimal and length = 4
*
@@ -0,0 +1,34 @@
<div class="project-tile">
<div class="project-tile-content">
<div class="top-bar">
<div class="status">
<div *ngIf="project.status === true" class="status-badge active">
<span>Active</span>
</div>
<div *ngIf="project.status === false" class="status-badge deactivated">
<span>Deactivated</span>
</div>
</div>
<div *ngIf="sysAdmin" class="settings">
<button class="settings-button" mat-icon-button (click)="navigateTo(project.shortcode, 'settings')">
<mat-icon>settings</mat-icon>
</button>
</div>
</div>

<div class="icon">
<mat-icon>redeem</mat-icon>
</div>

<div class="title">
<p>{{project.longname}}</p>
</div>

<div class="dashboard-button-container">
<button class="dashboard-button" mat-flat-button [color]="'primary'"
(click)="navigateTo(project.shortcode, 'dashboard')">
Go to dashboard
</button>
</div>
</div>
</div>
@@ -0,0 +1,97 @@
.project-tile {
border: 1px solid #d1d5db;
border-radius: 6px;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);

.project-tile-content {
padding: 10px 5px 10px 10px;

.top-bar {
display: flex;
justify-content: space-between;
align-items: center;

.status,
.settings {
display: inline-block;
}

.status {

.status-badge {
border-radius: 10px;
padding: 2px 10px 4px 10px;

span {
font-size: 12px;
}
}

.status-badge.active {
background-color: #99F6E4;

span {
color: #0F766E;
}
}

.status-badge.deactivated {
background-color: #E5E7EB;

span {
color: #6B7280;
}
}

}

.settings {
mat-icon-button {
width: 28px;
height: 28px;
line-height: 28px;
mat-icon {
height: 28px;
width: 28px;
font-size: 28px;
line-height: 28px;
}
}

}
}

.icon {
padding-top: 23px;

mat-icon {
font-size: 40px;
}
}

.title {
font-weight: 700;
font-size: 24px;
color: #3b4856;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
line-height: 28px;
padding: 0px 20px;
height: 80px;
}

.dashboard-button-container {
margin: 14% 0%;

button {
font-size: 16px;
line-height: 24px;
font-weight: 400;
padding: 13px 21px;
}
}
}

}

0 comments on commit a64359b

Please sign in to comment.