Skip to content

Commit 814ef65

Browse files
ryanslattenClinton Werth
andauthored
Admin Teams dashboard component upgrade from AngularJS to Angular 14 (#306)
Updates the Teams component to Angular 14 --------- Co-authored-by: Clinton Werth <clinton@MacBook-Pro.local>
1 parent 0355723 commit 814ef65

19 files changed

Lines changed: 1164 additions & 4 deletions

service/src/models/team.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ exports.getTeams = async function(options, callback) {
360360
}
361361
}
362362

363-
let baseQuery = Team.find(conditions).sort('_id');
363+
const sortoptions = options.sort ? JSON.parse(options.sort) : { _id: 1 };
364+
let baseQuery = Team.find(conditions).sort(sortoptions);
364365
if (options.populate == null || options.populate == 'true') {
365366
baseQuery = baseQuery.populate('userIds');
366367
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { NgModule } from '@angular/core';
2+
import { CommonModule } from '@angular/common';
3+
import { RouterModule, Routes } from '@angular/router';
4+
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
5+
import { MatTableModule } from '@angular/material/table';
6+
import { MatPaginatorModule } from '@angular/material/paginator';
7+
import { MatSortModule } from '@angular/material/sort';
8+
import { MatDialogModule } from '@angular/material/dialog';
9+
import { MatFormFieldModule } from '@angular/material/form-field';
10+
import { MatInputModule } from '@angular/material/input';
11+
import { MatButtonModule } from '@angular/material/button';
12+
13+
import { TeamDashboardComponent } from './dashboard/team-dashboard.component';
14+
import { CreateTeamDialogComponent } from './create-team/create-team.component';
15+
import { TeamsService } from './teams-service';
16+
import { CoreModule } from '../../core/core.module';
17+
18+
const routes: Routes = [
19+
{
20+
path: '',
21+
component: TeamDashboardComponent
22+
}
23+
];
24+
25+
@NgModule({
26+
declarations: [
27+
TeamDashboardComponent,
28+
CreateTeamDialogComponent
29+
],
30+
imports: [
31+
CommonModule,
32+
FormsModule,
33+
CoreModule,
34+
ReactiveFormsModule,
35+
MatTableModule,
36+
MatPaginatorModule,
37+
MatSortModule,
38+
MatDialogModule,
39+
MatFormFieldModule,
40+
MatInputModule,
41+
MatButtonModule,
42+
RouterModule.forChild(routes)
43+
],
44+
providers: [
45+
TeamsService
46+
],
47+
entryComponents: [
48+
CreateTeamDialogComponent
49+
]
50+
})
51+
export class AdminTeamsModule { }
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<div class="admin-team-create">
2+
<h1 mat-dialog-title>New Team</h1>
3+
<div mat-dialog-content>
4+
<div *ngIf="errorMessage" class="error-message" style="color: red; margin-bottom: 16px;">
5+
{{ errorMessage }}
6+
</div>
7+
<form [formGroup]="teamForm">
8+
<mat-form-field class="full-width">
9+
<mat-label>Name</mat-label>
10+
<input matInput formControlName="name" required>
11+
<mat-error *ngIf="teamForm.get('name').hasError('required')">
12+
Name is required
13+
</mat-error>
14+
</mat-form-field>
15+
<mat-form-field class="full-width">
16+
<mat-label>Description</mat-label>
17+
<textarea matInput formControlName="description"></textarea>
18+
</mat-form-field>
19+
</form>
20+
</div>
21+
<div mat-dialog-actions>
22+
<button mat-button (click)="cancel()">Cancel</button>
23+
<button mat-button color="primary" (click)="save()" [disabled]="teamForm.invalid">Save</button>
24+
</div>
25+
</div>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
.full-width {
2+
width: 100%;
3+
}
4+
5+
.admin-team-create {
6+
display: flex;
7+
flex-direction: column;
8+
height: 100%;
9+
justify-content: space-around;
10+
}
11+
12+
.mat-dialog-actions {
13+
display: flex;
14+
justify-content: flex-end;
15+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Component, Inject } from '@angular/core';
2+
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
3+
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
4+
import { TeamsService } from '../teams-service';
5+
import { Team } from '../team';
6+
7+
/**
8+
* Dialog component for creating new teams.
9+
* Provides a form interface with validation for team name (required) and description (optional).
10+
*/
11+
@Component({
12+
selector: 'mage-admin-team-create',
13+
templateUrl: './create-team.component.html',
14+
styleUrls: ['./create-team.component.scss']
15+
})
16+
export class CreateTeamDialogComponent {
17+
teamForm: FormGroup;
18+
errorMessage: string = '';
19+
20+
constructor(
21+
public dialogRef: MatDialogRef<CreateTeamDialogComponent>,
22+
@Inject(MAT_DIALOG_DATA) public data: { team: Partial<Team> },
23+
private fb: FormBuilder,
24+
private teamsService: TeamsService
25+
) {
26+
this.teamForm = this.fb.group({
27+
name: [data.team.name || '', [Validators.required]],
28+
description: [data.team.description || '']
29+
});
30+
}
31+
32+
/**
33+
* Handles form submission for creating a new team.
34+
* Validates the form, creates the team via the teams service, and closes the dialog on success.
35+
*/
36+
save(): void {
37+
if (this.teamForm.invalid) {
38+
this.errorMessage = 'Please fill in all required fields.';
39+
return;
40+
}
41+
42+
this.errorMessage = '';
43+
const teamData = this.teamForm.value;
44+
this.teamsService.createTeam(teamData).subscribe({
45+
next: (newTeam) => {
46+
this.dialogRef.close(newTeam);
47+
},
48+
error: () => {
49+
this.errorMessage = 'Failed to create team. Please try again.';
50+
}
51+
});
52+
}
53+
54+
/**
55+
* Closes the dialog without saving any data or making any changes.
56+
*/
57+
cancel(): void {
58+
this.dialogRef.close();
59+
}
60+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<div class="admin-nav-gap">
2+
<div class="container-fluid">
3+
<ol class="breadcrumb">
4+
<li class="active"><i class="fa fa-users"></i> Teams</li>
5+
</ol>
6+
</div>
7+
</div>
8+
9+
<div class="container bottom-gap-l">
10+
<mage-card-navbar [title]="'Teams'" [isSearchable]="true" [searchPlaceholder]="'Search teams...'"
11+
[actionButtons]="actionButtons" (searchTermChanged)="onSearchTermChanged($event)"
12+
(searchCleared)="onSearchCleared()"></mage-card-navbar>
13+
14+
<div class="col-md-12 mat-elevation-z1 w-100">
15+
<table mat-table [class.mat-table]="true" [dataSource]="dataSource" class="mat-table-even-columns">
16+
<ng-container matColumnDef="name">
17+
<th mat-header-cell *matHeaderCellDef>Name</th>
18+
<td mat-cell *matCellDef="let team">
19+
<div class="strong">{{ team.name }}</div>
20+
</td>
21+
</ng-container>
22+
23+
<ng-container matColumnDef="description">
24+
<th mat-header-cell *matHeaderCellDef>Description</th>
25+
<td mat-cell *matCellDef="let team">
26+
<div class="muted description-cell" [title]="team.description">{{ team.description }}</div>
27+
</td>
28+
</ng-container>
29+
30+
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
31+
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="gotoTeam(row)" class="pointer"></tr>
32+
</table>
33+
<mat-paginator [length]="totalTeams" [pageSize]="pageSize" [pageSizeOptions]="pageSizeOptions"
34+
(page)="onPageChange($event)">
35+
</mat-paginator>
36+
</div>
37+
</div>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
.mat-table-even-columns {
2+
table-layout: fixed;
3+
width: 100%;
4+
5+
.mat-row {
6+
height: 3.75rem;
7+
}
8+
9+
.mat-cell {
10+
text-overflow: ellipsis;
11+
white-space: nowrap;
12+
overflow: hidden;
13+
}
14+
15+
.mat-cell,
16+
.mat-header-cell {
17+
font-size: 1em;
18+
padding: 1rem 0.75rem;
19+
}
20+
21+
.mat-header-cell {
22+
font-weight: 600;
23+
color: rgba(0, 0, 0, 0.87);
24+
}
25+
26+
.description-cell {
27+
display: -webkit-box;
28+
-webkit-line-clamp: 3;
29+
line-clamp: 3;
30+
-webkit-box-orient: vertical;
31+
overflow: hidden;
32+
text-overflow: ellipsis;
33+
white-space: normal;
34+
line-height: 1.1em;
35+
height: calc(3 * 1.1em);
36+
align-content: center;
37+
}
38+
}
39+
40+
.table-container {
41+
position: relative;
42+
}

0 commit comments

Comments
 (0)