Skip to content

Commit cc1b2ef

Browse files
committed
store
1 parent 83dae53 commit cc1b2ef

14 files changed

+660
-241
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { Injectable } from '@angular/core';
2+
import { HttpClient, HttpParams } from '@angular/common/http';
3+
import { Observable } from 'rxjs';
4+
import { User } from '@ngageoint/mage.web-core-lib/user';
5+
6+
export interface SearchOptions {
7+
populate?: boolean;
8+
limit?: number;
9+
sort?: { [key: string]: 1 | -1 };
10+
omit_event_teams?: boolean;
11+
term?: string;
12+
start?: string;
13+
id?: string;
14+
}
15+
16+
@Injectable({
17+
providedIn: 'root'
18+
})
19+
export class EventsService {
20+
21+
constructor(private http: HttpClient) { }
22+
23+
getEvents(options: SearchOptions): Observable<any> {
24+
let params = new HttpParams();
25+
26+
if (options.populate !== undefined) {
27+
params = params.set('populate', String(options.populate));
28+
}
29+
if (options.limit !== undefined) {
30+
params = params.set('limit', String(options.limit));
31+
}
32+
if (options.sort !== undefined) {
33+
params = params.set('sort', JSON.stringify(options.sort));
34+
}
35+
if (options.omit_event_teams !== undefined) {
36+
params = params.set('omit_event_teams', String(options.omit_event_teams));
37+
}
38+
if (options.term !== undefined) {
39+
params = params.set('term', options.term);
40+
}
41+
if (options.start !== undefined) {
42+
params = params.set('start', options.start);
43+
}
44+
45+
return this.http.get('/api/events', { params });
46+
}
47+
48+
getNonMembers(options: SearchOptions): Observable<User[]> {
49+
let params = new HttpParams();
50+
51+
if (options.populate !== undefined) {
52+
params = params.set('populate', String(options.populate));
53+
}
54+
if (options.limit !== undefined) {
55+
params = params.set('limit', String(options.limit));
56+
}
57+
if (options.sort !== undefined) {
58+
params = params.set('sort', JSON.stringify(options.sort));
59+
}
60+
if (options.omit_event_teams !== undefined) {
61+
params = params.set('omit_event_teams', String(options.omit_event_teams));
62+
}
63+
if (options.term !== undefined) {
64+
params = params.set('term', options.term);
65+
}
66+
if (options.start !== undefined) {
67+
params = params.set('start', options.start);
68+
}
69+
70+
return this.http.get<User[]>(`/api/events/${options.id}/nonMembers`, { params });
71+
}
72+
}

web-app/admin/src/app/admin/admin-teams/admin-teams.module.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,17 @@ import { MatButtonModule } from '@angular/material/button';
1212
import { TeamDashboardComponent } from './dashboard/team-dashboard.component';
1313
import { CreateTeamDialogComponent } from './create-team/create-team.component';
1414
import { TeamsService } from './teams-service';
15+
import { EventsService } from '../admin-event/events.service';
1516
import { TeamDetailsComponent } from './team-details/team-details.component';
1617
import { CoreModule } from '../../core/core.module';
18+
import { DeleteTeamComponent } from './delete-team/delete-team.component';
1719

1820
@NgModule({
1921
declarations: [
2022
TeamDashboardComponent,
2123
CreateTeamDialogComponent,
22-
TeamDetailsComponent
24+
TeamDetailsComponent,
25+
DeleteTeamComponent
2326
],
2427
imports: [
2528
CommonModule,
@@ -35,10 +38,12 @@ import { CoreModule } from '../../core/core.module';
3538
MatButtonModule
3639
],
3740
providers: [
38-
TeamsService
41+
TeamsService,
42+
EventsService
3943
],
4044
entryComponents: [
41-
CreateTeamDialogComponent
45+
CreateTeamDialogComponent,
46+
DeleteTeamComponent
4247
]
4348
})
4449
export class AdminTeamsModule { }

web-app/admin/src/app/admin/admin-teams/dashboard/team-dashboard.component.html

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@
77
</div>
88

99
<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>
10+
<div class="page-header">
11+
<h2 class="page-title">Teams</h2>
12+
<p class="page-subtitle">Manage and organize your teams</p>
13+
</div>
14+
15+
<div class="navbar-container">
16+
<mage-card-navbar [isSearchable]="true" [searchPlaceholder]="'Search teams...'" [actionButtons]="actionButtons"
17+
(searchTermChanged)="onSearchTermChanged($event)" (searchCleared)="onSearchCleared()"></mage-card-navbar>
18+
</div>
1319

14-
<div class="col-md-12 mat-elevation-z1 w-100">
20+
<div class="table-wrapper mat-elevation-z2">
1521
<table mat-table [class.mat-table]="true" [dataSource]="dataSource" class="mat-table-even-columns">
1622
<ng-container matColumnDef="name">
1723
<th mat-header-cell *matHeaderCellDef>Name</th>

web-app/admin/src/app/admin/admin-teams/dashboard/team-dashboard.component.scss

Lines changed: 106 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,137 @@
1+
// Modern page header styling
2+
.page-header {
3+
margin-bottom: 2rem;
4+
padding: 0;
5+
6+
.page-title {
7+
font-size: 2rem;
8+
font-weight: 700;
9+
color: #1a1a1a;
10+
margin: 0 0 0.5rem 0;
11+
line-height: 1.2;
12+
letter-spacing: -0.025em;
13+
}
14+
15+
.page-subtitle {
16+
font-size: 1rem;
17+
color: #666;
18+
margin: 0;
19+
line-height: 1.5;
20+
font-weight: 400;
21+
}
22+
}
23+
24+
// Modern navbar container
25+
.navbar-container {
26+
margin-bottom: 1.5rem;
27+
28+
mage-card-navbar {
29+
border-radius: 12px;
30+
overflow: hidden;
31+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
32+
}
33+
}
34+
35+
// Modern table wrapper
36+
.table-wrapper {
37+
border-radius: 12px;
38+
overflow: hidden;
39+
background: white;
40+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
41+
border: 1px solid #e5e7eb;
42+
}
43+
144
.mat-table-even-columns {
245
table-layout: fixed;
346
width: 100%;
47+
background: white;
448

549
.mat-row {
6-
height: 3.75rem;
50+
height: 4rem;
51+
transition: background-color 0.2s ease;
52+
53+
&:hover {
54+
background-color: #f8fafc;
55+
}
56+
57+
&.pointer {
58+
cursor: pointer;
59+
}
760
}
861

962
.mat-cell {
1063
text-overflow: ellipsis;
1164
white-space: nowrap;
1265
overflow: hidden;
66+
border-bottom: 1px solid #f1f5f9;
1367
}
1468

1569
.mat-cell,
1670
.mat-header-cell {
17-
font-size: 1em;
18-
padding: 1rem 0.75rem;
71+
font-size: 0.875rem;
72+
padding: 1rem 1.5rem;
1973
}
2074

2175
.mat-header-cell {
2276
font-weight: 600;
23-
color: rgba(0, 0, 0, 0.87);
77+
color: #374151;
78+
background-color: #f9fafb;
79+
border-bottom: 2px solid #e5e7eb;
80+
text-transform: uppercase;
81+
font-size: 0.75rem;
82+
letter-spacing: 0.05em;
2483
}
2584

2685
.description-cell {
2786
display: -webkit-box;
28-
-webkit-line-clamp: 3;
29-
line-clamp: 3;
87+
-webkit-line-clamp: 2;
88+
line-clamp: 2;
3089
-webkit-box-orient: vertical;
3190
overflow: hidden;
3291
text-overflow: ellipsis;
3392
white-space: normal;
34-
line-height: 1.1em;
35-
height: calc(3 * 1.1em);
93+
line-height: 1.4em;
94+
height: calc(2 * 1.4em);
3695
align-content: center;
96+
color: #6b7280;
97+
}
98+
99+
.strong {
100+
font-weight: 600;
101+
color: #111827;
102+
}
103+
104+
.muted {
105+
color: #6b7280;
106+
}
107+
}
108+
109+
// Modern paginator styling
110+
::ng-deep .mat-paginator {
111+
border-top: 1px solid #e5e7eb;
112+
background-color: #f9fafb;
113+
114+
.mat-paginator-container {
115+
padding: 0 1.5rem;
116+
min-height: 3.5rem;
117+
}
118+
119+
.mat-paginator-page-size,
120+
.mat-paginator-range-label {
121+
font-size: 0.875rem;
122+
color: #6b7280;
123+
}
124+
125+
.mat-icon-button {
126+
color: #6b7280;
127+
128+
&:hover {
129+
background-color: #e5e7eb;
130+
}
131+
132+
&[disabled] {
133+
color: #d1d5db;
134+
}
37135
}
38136
}
39137

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<div class="modal-header">
2+
<h3 class="modal-title">Delete "{{team.name}}"</h3>
3+
</div>
4+
5+
<div class="modal-body">
6+
<div class="row">
7+
<div class="col-md-12">
8+
<p class="mb-3">Team "{{team.name}}" will be deleted.</p>
9+
</div>
10+
</div>
11+
12+
<div class="row">
13+
<div class="col-md-12">
14+
<div class="checkbox mb-3">
15+
<label>
16+
<input type="checkbox" [(ngModel)]="deleteAllUsers"> Delete all users that are a part of this team.
17+
</label>
18+
</div>
19+
20+
<div class="mt-3 p-3 bg-danger-light border border-danger rounded" *ngIf="deleteAllUsers">
21+
<h4 class="text-danger mb-3">Are you ABSOLUTELY sure?</h4>
22+
<p class="mb-2">This will delete all users that are part of this team, regardless of if they are in
23+
other teams. This action <strong>CANNOT</strong> be undone.</p>
24+
<p class="mb-3">Please type in the name of the team to confirm.</p>
25+
<input type="text" class="form-control" [(ngModel)]="confirm.text" placeholder="Type team name here">
26+
</div>
27+
</div>
28+
</div>
29+
</div>
30+
31+
<div class="modal-footer d-flex justify-content-end">
32+
<button class="btn btn-default me-2" (click)="cancel()">Cancel</button>
33+
<button class="btn btn-danger" *ngIf="!deleteAllUsers" (click)="deleteTeam()">
34+
<i class="icon-trash me-1"></i> Delete Team
35+
</button>
36+
<button class="btn btn-danger" *ngIf="deleteAllUsers" [disabled]="deleting || team.name !== confirm.text"
37+
(click)="deleteTeam()">
38+
<i class="fa me-1" [ngClass]="deleting ? 'fa-spinner fa-spin' : 'fa-trash'"></i> Delete Team and Users
39+
</button>
40+
</div>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
.modal-body {
2+
width: 100%;
3+
padding: 1rem;
4+
}
5+
6+
.bg-danger-light {
7+
background-color: #f8d7da !important;
8+
}
9+
10+
.me-1 {
11+
margin-right: 0.25rem;
12+
}
13+
14+
.me-2 {
15+
margin-right: 0.5rem;
16+
}
17+
18+
.mb-2 {
19+
margin-bottom: 0.5rem;
20+
}
21+
22+
.mb-3 {
23+
margin-bottom: 1rem;
24+
}
25+
26+
.mt-3 {
27+
margin-top: 1rem;
28+
}
29+
30+
.p-3 {
31+
padding: 1rem;
32+
}
33+
34+
.d-flex {
35+
display: flex;
36+
}
37+
38+
.justify-content-end {
39+
justify-content: flex-end;
40+
}
41+
42+
.border {
43+
border: 1px solid;
44+
}
45+
46+
.border-danger {
47+
border-color: #dc3545;
48+
}
49+
50+
.rounded {
51+
border-radius: 0.375rem;
52+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { DeleteTeamComponent } from './delete-team.component';
4+
5+
describe('DeleteTeamComponent', () => {
6+
let component: DeleteTeamComponent;
7+
let fixture: ComponentFixture<DeleteTeamComponent>;
8+
9+
beforeEach(async () => {
10+
await TestBed.configureTestingModule({
11+
declarations: [ DeleteTeamComponent ]
12+
})
13+
.compileComponents();
14+
15+
fixture = TestBed.createComponent(DeleteTeamComponent);
16+
component = fixture.componentInstance;
17+
fixture.detectChanges();
18+
});
19+
20+
it('should create', () => {
21+
expect(component).toBeTruthy();
22+
});
23+
});

0 commit comments

Comments
 (0)