Skip to content

Commit

Permalink
Add 'Support Tools' to ticket details screen.
Browse files Browse the repository at this point in the history
  • Loading branch information
sei-bstein committed Feb 5, 2024
1 parent 97aa61a commit 3e7292c
Show file tree
Hide file tree
Showing 23 changed files with 285 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ import { ManageManualChallengeBonusesModalComponent } from '../components/manage
import { TeamService } from '@/api/team.service';
import { TeamAdminContextMenuSessionResetRequest } from '../components/team-admin-context-menu/team-admin-context-menu.component';
import { AppTitleService } from '@/services/app-title.service';
import { UnsubscriberService } from '@/services/unsubscriber.service';

@Component({
selector: 'app-player-registrar',
templateUrl: './player-registrar.component.html',
styleUrls: ['./player-registrar.component.scss']
styleUrls: ['./player-registrar.component.scss'],
providers: [UnsubscriberService]
})
export class PlayerRegistrarComponent {
refresh$ = new BehaviorSubject<boolean>(true);
Expand All @@ -32,7 +34,9 @@ export class PlayerRegistrarComponent {
selected: Player[] = [];
viewed?: Player;
viewChange$ = new BehaviorSubject<Player | undefined>(this.viewed);
search: PlayerSearch = { term: '', take: 100, filter: ['collapse'], sort: 'time', mode: 'competition' };
// we'd ideally constrain the max ("take") here, but this is the only place we provide player counts
// (see https://github.com/cmu-sei/Gameboard/issues/372)
search: PlayerSearch = { term: '', take: 0, filter: ['collapse'], sort: 'time', mode: 'competition' };
filter = '';
teamView = 'collapse';
scope = '';
Expand Down Expand Up @@ -65,7 +69,8 @@ export class PlayerRegistrarComponent {
private clipboard: ClipboardService,
private teamService: TeamService,
private title: AppTitleService,
private unityService: UnityService
private unityService: UnityService,
private unsub: UnsubscriberService
) {

const game$ = route.params.pipe(
Expand Down Expand Up @@ -107,6 +112,17 @@ export class PlayerRegistrarComponent {
]).pipe(
map(([game, players, futures]) => ({ game, players, futures }))
);

this.unsub.add(route.queryParams.subscribe(param => {
if (param?.term) {
this.mode = "";
this.teamView = "";
this.search.filter = [this.filter];
this.search.mode = "";
this.search.term = param.term;
this.refresh$.next(true);
}
}));
}

toggleFilter(role: string): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ export interface IModalReady<TModalContext> {
context: TModalContext;
}

export interface ModalConfig<TComponent, TContext> {
export interface ModalConfig<TComponent> {
content: ModalContent<TComponent>;
context: TContext;
context: Partial<TComponent>;
modalClasses?: string[];
isBackdropStatic?: boolean;
ignoreBackdropClick?: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { SimpleEntity } from '@/api/models';
import { ModalConfirmService } from '@/services/modal-confirm.service';
import { Component } from '@angular/core';

@Component({
template: `
<div class="modal-confirm-component">
<div class="modal-header">
<div class="titles-container">
<h4 class="modal-title pull-left">{{ team?.name }}</h4>
<h5 class="gray-text">Challenge Timeline: {{game?.name}}</h5>
</div>
<button type="button" class="btn-close close pull-right" aria-label="Close" (click)="close()">
<span aria-hidden="true" class="visually-hidden">&times;</span>
</button>
</div>
<div class="modal-body" *ngIf="team?.id">
<app-team-event-horizon [teamId]="team?.id"></app-team-event-horizon>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-info" (click)="close()">OK</button>
</div>
</div>
`,
selector: 'app-event-horizon-modal',
styleUrls: ['./event-horizon-modal.component.scss']
})
export class EventHorizonModalComponent {
team?: SimpleEntity;
game?: SimpleEntity;

constructor(private modalService: ModalConfirmService) { }

protected close() {
this.modalService.hide();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import { LogService } from '@/services/log.service';
import { ModalConfirmService } from '@/services/modal-confirm.service';
import { AfterViewInit, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { DateTime } from 'luxon';
import { DataGroup, DataGroupCollectionType, Timeline } from 'vis-timeline/esnext';
import { Timeline } from 'vis-timeline/esnext';

@Component({
selector: 'app-team-event-horizon',
templateUrl: './team-event-horizon.component.html',
styleUrls: ['./team-event-horizon.component.scss']
})
export class TeamEventHorizonComponent implements OnInit, AfterViewInit, OnDestroy {
@Input() teamId = "";
@Input() teamId?: string;
@ViewChild("timelineContainer") timelineContainer?: ElementRef;

protected selectedEventTypes: EventHorizonEventType[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { TeamEventHorizonComponent } from './components/team-event-horizon/team-event-horizon.component';
import { CoreModule } from '@/core/core.module';
import { EventTypeToFriendlyNamePipe } from './pipes/event-type-to-friendly-name.pipe';
import { EventHorizonModalComponent } from './components/event-horizon-modal/event-horizon-modal.component';

const PUBLIC_DECLARATIONS = [
TeamEventHorizonComponent
Expand All @@ -12,6 +13,7 @@ const PUBLIC_DECLARATIONS = [
declarations: [
...PUBLIC_DECLARATIONS,
EventTypeToFriendlyNamePipe,
EventHorizonModalComponent,
],
imports: [
CommonModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@ export class ScoreboardComponent implements OnChanges {
}

protected handleRowClick(gameInfo: GameScoreGameInfo, teamScore: GameScoreTeam) {
this.modalConfirmService.openComponent<ScoreboardTeamDetailModalComponent, ScoreboardTeamDetailModalContext>({
this.modalConfirmService.openComponent<ScoreboardTeamDetailModalComponent>({
content: ScoreboardTeamDetailModalComponent,
context: {
game: { id: gameInfo.id, name: gameInfo.name },
teamData: teamScore
context: {
game: { id: gameInfo.id, name: gameInfo.name },
teamData: teamScore
}
},
modalClasses: [
teamScore.players.length > 1 ? "modal-xl" : "modal-lg",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ interface LegacyFeedbackFormContext {
providers: [UnsubscriberService]
})
export class PracticeChallengeSolvedModalComponent implements OnInit {
protected context?: PracticeChallengeSolvedModalContext;
context?: PracticeChallengeSolvedModalContext;
protected certificateUrl?: string;
protected isCertificateConfigured = false;
protected feedbackFormContext?: LegacyFeedbackFormContext = undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,9 @@ export class PracticeSessionComponent {
this.modalService.openComponent({
content: PracticeChallengeSolvedModalComponent,
context: {
challenge
context: {
challenge
}
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ export class EnrollmentReportByGameComponent implements OnChanges {
}

protected handleSponsorsCountClick(game: ReportGame, sponsors: EnrollmentReportByGameSponsor[]) {
this.modalService.openComponent<EnrollmentReportSponsorPlayerCountModalComponent, EnrollmentReportSponsorPlayerCountModalContext>({
this.modalService.openComponent<EnrollmentReportSponsorPlayerCountModalComponent>({
content: EnrollmentReportSponsorPlayerCountModalComponent,
context: {
game: { id: game.id, name: game.name },
sponsors: sponsors,
context: {
game: { id: game.id, name: game.name },
sponsors: sponsors,
}
},
modalClasses: ["modal-xl"]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,20 @@ export class PlayersReportComponent extends ReportComponentBase<PlayersReportFla
}

protected showPlayerParticipation(record: PlayersReportRecord) {
this.modalService.openComponent<PlayersReportParticipationSummaryComponent, PlayersReportParticipationSummaryContext>({
this.modalService.openComponent<PlayersReportParticipationSummaryComponent>({
content: PlayersReportParticipationSummaryComponent,
context: {
player: {
id: record.user.id,
name: record.user.name,
sponsor: record.sponsor
},
series: record.distinctSeriesPlayed,
seasons: record.distinctSeasonsPlayed,
tracks: record.distinctTracksPlayed,
games: record.distinctGamesPlayed
context: {
player: {
id: record.user.id,
name: record.user.name,
sponsor: record.sponsor
},
series: record.distinctSeriesPlayed,
seasons: record.distinctSeasonsPlayed,
tracks: record.distinctTracksPlayed,
games: record.distinctGamesPlayed
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,13 @@ export class PracticeModeReportByChallengeComponent implements OnChanges {
throw new Error("Couldn't resolve the sponsor performance template.");
}

this.modalService.openComponent<SponsorChallengePerformanceComponent, SponsorChallengePerformanceModalContext>({
this.modalService.openComponent<SponsorChallengePerformanceComponent>({
content: SponsorChallengePerformanceComponent,
context: {
challenge,
sponsorPerformance
context: {
challenge,
sponsorPerformance
}
},
modalClasses: ["modal-dialog-centered", "modal-xl"]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class PracticeModeReportByPlayerModePerformanceComponent implements OnCha
protected totalAttemptsClicked(event: { userId: string, isPractice: boolean }) {
this.modalService.openComponent({
content: PlayerModePerformanceSummaryComponent,
context: event as PlayerModePerformanceSummaryContext,
context: { context: { ...event } },
modalClasses: ["modal-dialog-centered", "modal-lg"]
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,25 @@ export class PracticeModeReportByUserComponent implements OnChanges {
}

protected showAttemptsSummary(record: PracticeModeReportByUserRecord): void {
this.modalService.openComponent<PlayerChallengeAttemptsModalComponent, PlayerChallengeAttempts>({
this.modalService.openComponent<PlayerChallengeAttemptsModalComponent>({
content: PlayerChallengeAttemptsModalComponent,
context: {
player: {
name: record.user.name,
sponsor: record.user.sponsor,
},
subtitle: `Practice Challenge: ${record.challenge.name}`,
subtitleDetail: record.challenge.game.name,
attempts: record.attempts.map(a => ({
challengeSpec: { id: record.challenge.id, name: record.challenge.name },
game: record.challenge.game,
maxPossibleScore: record.challenge.maxPossibleScore,
result: a.result,
score: a.score || 0,
startDate: a.start
}))
context: {
player: {
name: record.user.name,
sponsor: record.user.sponsor,
},
subtitle: `Practice Challenge: ${record.challenge.name}`,
subtitleDetail: record.challenge.game.name,
attempts: record.attempts.map(a => ({
challengeSpec: { id: record.challenge.id, name: record.challenge.name },
game: record.challenge.game,
maxPossibleScore: record.challenge.maxPossibleScore,
result: a.result,
score: a.score || 0,
startDate: a.start
}))
}
},
modalClasses: ["modal-dialog-centered", "modal-md"]
});
Expand Down
12 changes: 8 additions & 4 deletions projects/gameboard-ui/src/app/services/modal-confirm.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ export class ModalConfirmService implements OnDestroy {
}

openConfirm(config: ModalConfirmConfig): void {
this.bsModalRef = this.openWithDefaultStyles({ content: ModalConfirmComponent, context: config as ModalConfirmConfig, modalClasses: config.modalClasses });
this.bsModalRef = this.openWithDefaultStyles({
content: ModalConfirmComponent,
context: { context: config },
modalClasses: config.modalClasses
});
}

openComponent<TComponent, TContext>(config: ModalConfig<TComponent, TContext>) {
openComponent<TComponent>(config: ModalConfig<TComponent>) {
this.bsModalRef = this.openWithDefaultStyles(config);
}

Expand All @@ -37,12 +41,12 @@ export class ModalConfirmService implements OnDestroy {
this.cleanupModalRef();
}

private openWithDefaultStyles<TComponent, TContext>(config: ModalConfig<TComponent, TContext>) {
private openWithDefaultStyles<TComponent>(config: ModalConfig<TComponent>) {
if (this.bsModalRef)
this.hide();

return this.bsModalService.show(config.content, {
initialState: { context: { ...config.context } } as unknown as Partial<TComponent>,
initialState: config.context as unknown as Partial<TComponent>,
class: config.modalClasses?.join(" ") || "modal-dialog-centered",
ignoreBackdropClick: config.ignoreBackdropClick || false,
scrollable: true
Expand Down
8 changes: 8 additions & 0 deletions projects/gameboard-ui/src/app/services/router.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ export class RouterService implements OnDestroy {
this.router.navigateByUrl("/");
}

public getAdminChallengeUrl(challengeId: string) {
return this.router.createUrlTree(["admin", "support"], { queryParams: { search: challengeId } }).toString();
}

public getAdminGamePlayerUrl(gameId: string, playerId: string) {
return this.router.createUrlTree(["admin", "registrar", gameId], { queryParams: { term: playerId } });
}

public getCertificatePrintableUrl(mode: PlayerMode, challengeSpecOrGameId: string) {
const localUserId = this.localUser.user$.value?.id;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.btn-link {
margin: 0;
padding: 0;
}

li {
margin-left: 1rem;
list-style-type: square;
}
Loading

0 comments on commit 3e7292c

Please sign in to comment.