Skip to content

Commit

Permalink
#705 refactor front end to reuse sidepanel in every module.
Browse files Browse the repository at this point in the history
+ create simple member-detail component and navigate from member-list to it
+ add hover effects to okr-table
  • Loading branch information
janikEndtner committed Jan 5, 2024
1 parent 34469c4 commit 39685c2
Show file tree
Hide file tree
Showing 21 changed files with 137 additions and 62 deletions.
41 changes: 16 additions & 25 deletions frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
import { inject, NgModule } from '@angular/core';
import { ActivatedRouteSnapshot, ResolveFn, RouterModule, Routes } from '@angular/router';
import { ResolveFn, RouterModule, Routes } from '@angular/router';
import { OverviewComponent } from './components/overview/overview.component';
import { EMPTY, of } from 'rxjs';
import { SidepanelComponent } from './components/sidepanel/sidepanel.component';
import { of } from 'rxjs';
import { SidepanelComponent } from './shared/sidepanel/sidepanel.component';
import { authGuard } from './guards/auth.guard';
import { UserService } from './services/user.service';
import { User } from './shared/types/model/User';
import { OAuthService } from 'angular-oauth2-oidc';

/**
* Resolver for get the id from url like `/objective/42` or `/keyresult/42`.
*/
export const getIdFromPathResolver: ResolveFn<number> = (route: ActivatedRouteSnapshot) => {
try {
let id = Number.parseInt(route.url[1].path);
return of(id);
} catch (error) {
console.error('Can not get id from URL:', error);
return EMPTY;
}
};
import { ObjectiveDetailComponent } from './components/objective-detail/objective-detail.component';
import { KeyresultDetailComponent } from './components/keyresult-detail/keyresult-detail.component';

const currentUserResolver: ResolveFn<User | undefined> = () => {
const oauthService = inject(OAuthService);
Expand All @@ -39,16 +28,18 @@ const routes: Routes = [
},
children: [
{
path: 'objective/:id',
component: SidepanelComponent,
resolve: { id: getIdFromPathResolver },
data: { type: 'Objective' },
},
{
path: 'keyresult/:id',
path: 'details',
component: SidepanelComponent,
resolve: { id: getIdFromPathResolver },
data: { type: 'KeyResult' },
children: [
{
path: 'objective/:id',
component: ObjectiveDetailComponent,
},
{
path: 'keyresult/:id',
component: KeyresultDetailComponent,
},
],
},
],
canActivate: [authGuard],
Expand Down
9 changes: 1 addition & 8 deletions frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { MomentDateAdapter } from '@angular/material-moment-adapter';
import { OAuthModule, OAuthService, OAuthStorage } from 'angular-oauth2-oidc';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { A11yModule } from '@angular/cdk/a11y';
import { MatRadioModule } from '@angular/material/radio';
import { ConfigService } from './config.service';
import { firstValueFrom } from 'rxjs';
Expand All @@ -41,7 +40,7 @@ import { MatSliderModule } from '@angular/material/slider';
import { MatDividerModule } from '@angular/material/divider';
import { ApplicationBannerComponent } from './components/application-banner/application-banner.component';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { CdkConnectedOverlay, CdkOverlayOrigin, OverlayModule } from '@angular/cdk/overlay';
import { OverlayModule } from '@angular/cdk/overlay';
import { QuarterFilterComponent } from './components/quarter-filter/quarter-filter.component';
import { TeamFilterComponent } from './components/team-filter/team-filter.component';
import { MatChipsModule } from '@angular/material/chips';
Expand All @@ -60,7 +59,6 @@ import { CheckInHistoryDialogComponent } from './components/check-in-history-dia
import { CheckInFormMetricComponent } from './components/checkin/check-in-form-metric/check-in-form-metric.component';
import { CheckInFormOrdinalComponent } from './components/checkin/check-in-form-ordinal/check-in-form-ordinal.component';
import { CheckInFormComponent } from './components/checkin/check-in-form/check-in-form.component';
import { SidepanelComponent } from './components/sidepanel/sidepanel.component';
import { ApplicationTopBarComponent } from './components/application-top-bar/application-top-bar.component';

function initOauthFactory(configService: ConfigService, oauthService: OAuthService) {
Expand Down Expand Up @@ -113,7 +111,6 @@ export const MY_FORMATS = {
CheckInFormMetricComponent,
CheckInFormOrdinalComponent,
CheckInFormComponent,
SidepanelComponent,
],
imports: [
CommonModule,
Expand Down Expand Up @@ -145,7 +142,6 @@ export const MY_FORMATS = {
},
}),
OAuthModule.forRoot(),
A11yModule,
MatRadioModule,
NgOptimizedImage,
MatSidenavModule,
Expand All @@ -154,9 +150,6 @@ export const MY_FORMATS = {
MatDividerModule,
MatSidenavModule,
MatCheckboxModule,
CdkOverlayOrigin,
CdkConnectedOverlay,
CdkOverlayOrigin,
MatChipsModule,
CdkDropList,
CdkDrag,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { KeyResultOrdinal } from '../../shared/types/model/KeyResultOrdinal';
import { CheckInHistoryDialogComponent } from '../check-in-history-dialog/check-in-history-dialog.component';
import { MatDialog } from '@angular/material/dialog';
import { BehaviorSubject, catchError, EMPTY } from 'rxjs';
import { Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { RefreshDataService } from '../../services/refresh-data.service';
import { CloseState } from '../../shared/types/enums/CloseState';
import { CheckInFormComponent } from '../checkin/check-in-form/check-in-form.component';
Expand Down Expand Up @@ -35,12 +35,22 @@ export class KeyresultDetailComponent implements OnInit {
private refreshDataService: RefreshDataService,
private dialog: MatDialog,
private router: Router,
private route: ActivatedRoute,
) {}

ngOnInit(): void {
this.keyResultId = this.getIdFromParams();
this.loadKeyResult(this.keyResultId);
}

private getIdFromParams(): number {
const id = this.route.snapshot.paramMap.get('id');
if (!id) {
throw Error('keyresult id is undefined');
}
return parseInt(id);
}

loadKeyResult(id: number): void {
this.keyResultService
.getFullKeyResult(id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ export class KeyresultComponent {
constructor(private router: Router) {}

openDrawer() {
this.router.navigate(['keyresult', this.keyResult.id]);
this.router.navigate(['details/keyresult', this.keyResult.id]);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
:host {
width: 100%;
}

.sub-title-objective {
font-size: 1rem;
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Objective } from '../../shared/types/model/Objective';
import { ObjectiveService } from '../../services/objective.service';
import { BehaviorSubject, catchError, EMPTY } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
import { RefreshDataService } from '../../services/refresh-data.service';
import { KeyresultDialogComponent } from '../keyresult-dialog/keyresult-dialog.component';
import { ObjectiveFormComponent } from '../../shared/dialog/objective-dialog/objective-form.component';
import { Router } from '@angular/router';
import { ActivatedRoute, Router } from '@angular/router';
import { OKR_DIALOG_CONFIG } from '../../shared/constantLibary';

@Component({
selector: 'app-objective-detail',
templateUrl: './objective-detail.component.html',
styleUrl: 'objective-detail.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ObjectiveDetailComponent {
@Input()
objectiveId!: number;
objective$: BehaviorSubject<Objective> = new BehaviorSubject<Objective>({} as Objective);

Expand All @@ -24,12 +24,22 @@ export class ObjectiveDetailComponent {
private dialog: MatDialog,
private refreshDataService: RefreshDataService,
private router: Router,
private route: ActivatedRoute,
) {}

ngOnInit(): void {
this.objectiveId = this.getIdFromParams();
this.loadObjective(this.objectiveId);
}

private getIdFromParams(): number {
const id = this.route.snapshot.paramMap.get('id');
if (!id) {
throw Error('objective id is undefined');
}
return parseInt(id);
}

loadObjective(id: number): void {
this.objectiveService
.getFullObjective(id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ export class ObjectiveComponent implements OnInit {
}

openObjectiveDetail() {
this.router.navigate(['objective', this.objective$.value.id]);
this.router.navigate(['details/objective', this.objective$.value.id]);
}

openAddKeyResultDialog() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
<img src="../../../assets/images/puzzle-p.svg" alt="" width="242" class="puzzle-logo" />
</div>
</div>
<router-outlet></router-outlet>
13 changes: 13 additions & 0 deletions frontend/src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import { MatRadioModule } from '@angular/material/radio';
import { MatIconModule } from '@angular/material/icon';
import { OkrTangramComponent } from './custom/okr-tangram/okr-tangram.component';
import { MatButtonModule } from '@angular/material/button';
import { SidepanelComponent } from './sidepanel/sidepanel.component';
import { MatSidenavModule } from '@angular/material/sidenav';
import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
import { A11yModule } from '@angular/cdk/a11y';
import { RouterOutlet } from '@angular/router';

@NgModule({
declarations: [
Expand All @@ -31,6 +36,7 @@ import { MatButtonModule } from '@angular/material/button';
CompleteDialogComponent,
DialogHeaderComponent,
OkrTangramComponent,
SidepanelComponent,
],
imports: [
CommonModule,
Expand All @@ -44,6 +50,12 @@ import { MatButtonModule } from '@angular/material/button';
MatIconModule,
NgOptimizedImage,
MatButtonModule,
MatSidenavModule,
CdkOverlayOrigin,
CdkConnectedOverlay,
CdkOverlayOrigin,
A11yModule,
RouterOutlet,
],
exports: [
ExampleDialogComponent,
Expand All @@ -56,6 +68,7 @@ import { MatButtonModule } from '@angular/material/button';
CompleteDialogComponent,
DialogHeaderComponent,
OkrTangramComponent,
SidepanelComponent,
],
})
export class SharedModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,12 @@
cdkScrollable="false"
cdkTrapFocus
class="bg-white w-100 sidepanel overflow-y-auto"
[ngClass]="{ right: loaded }"
[style.right]="right"
>
<div class="sidebar__content d-flex">
<div [ngSwitch]="modelType" class="d-flex flex-row w-100">
<div *ngSwitchDefault>Es ist eine Fehler aufgetreten!</div>
<app-objective-detail *ngSwitchCase="'Objective'" [objectiveId]="id" class="w-100"></app-objective-detail>
<app-keyresult-detail *ngSwitchCase="'KeyResult'" [keyResultId]="id" class="w-100"></app-keyresult-detail>
<div class="d-flex flex-row w-100 router-outlet-wrapper">
<router-outlet></router-outlet>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AfterViewInit,
AfterContentInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
OnDestroy,
Expand All @@ -16,9 +17,10 @@ import { ConnectedPosition } from '@angular/cdk/overlay'; // ESM
styleUrls: ['./sidepanel.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SidepanelComponent implements OnInit, AfterViewInit, OnDestroy {
export class SidepanelComponent implements OnInit, AfterContentInit, OnDestroy {
leaveKeys = ['Escape'];
right = '-100%';
loaded = false;
@ViewChild('sidebar')
sidebar!: ElementRef<HTMLDivElement>;
position: ConnectedPosition[] = [
Expand All @@ -29,32 +31,27 @@ export class SidepanelComponent implements OnInit, AfterViewInit, OnDestroy {
overlayY: 'top',
},
];
modelType = '';
id: number = 0;

constructor(
private activatedRoute: ActivatedRoute,
private router: Router,
private cd: ChangeDetectorRef,
private route: ActivatedRoute,
) {}

ngOnInit(): void {
this.activatedRoute.data.subscribe((data) => {
this.modelType = data['type'];
this.id = data['id'];
});
}

ngAfterViewInit(): void {
ngOnInit(): void {}
ngAfterContentInit(): void {
document.body.classList.add('disable-scrolling');
this.right = '0';
this.loaded = true;
this.cd.markForCheck();
}

ngOnDestroy() {
document.body.classList.remove('disable-scrolling');
}

close() {
this.router.navigate(['']);
this.router.navigate(['../'], { relativeTo: this.route });
}

closeOnKeydown($event: KeyboardEvent) {
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="w-100" cdkTrapFocus cdkTrapFocusAutoCapture="true" [attr.data-testId]="'side-panel'">
<p>test</p>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {Component, OnInit} from '@angular/core';

@Component({
selector: 'app-member-detail',
templateUrl: './member-detail.component.html',
styleUrl: './member-detail.component.css'
})
export class MemberDetailComponent implements OnInit {

constructor(
) {
}
ngOnInit(): void {
}



}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<div>
<div xmlns="http://www.w3.org/1999/html">
<div id="member-header">
<div class="title">
<h3 *ngIf="selectedTeam">
<span>{{ selectedTeam?.name }}</span>
<mat-icon class="mx-2 cursor-pointer" *ngIf="selectedTeam?.isWriteable" (click)="editTeam()">edit</mat-icon>
<span>{{ selectedTeam.name }}</span>
<mat-icon class="mx-2 cursor-pointer" *ngIf="selectedTeam.isWriteable" (click)="editTeam()">edit</mat-icon>
</h3>
<h3 *ngIf="!selectedTeam">Alle Teams</h3>
<p>Members: {{ dataSource.length }}</p>
Expand Down Expand Up @@ -65,7 +65,9 @@ <h3 *ngIf="!selectedTeam">Alle Teams</h3>

<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef>Name</th>
<td mat-cell *matCellDef="let element">{{ element.firstname }} {{ element.lastname }}</td>
<td mat-cell *matCellDef="let element">
<a [routerLink]="getMemberDetailsLink(element)"> {{ element.firstname }} {{ element.lastname }} </a>
</td>
</ng-container>

<ng-container matColumnDef="roles">
Expand All @@ -81,6 +83,11 @@ <h3 *ngIf="!selectedTeam">Alle Teams</h3>
</ng-container>

<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
<tr
mat-row
class="cursor-pointer"
[routerLink]="getMemberDetailsLink(row)"
*matRowDef="let row; columns: displayedColumns"
></tr>
</table>
</div>
Loading

0 comments on commit 39685c2

Please sign in to comment.