Skip to content

Commit

Permalink
v3.18.0 (#180)
Browse files Browse the repository at this point in the history
* Rebase to next

* Resolved issue that caused an automatic refresh on external game load.

* Fix stray refresh bug for external games

* Remove log

* Remove automatic iframe refresh

* Use behaviorsubject in the api status interceptor rather than startWith

* Copy challenge IDs on external game admin. Mild restyling.

* Fixed an issue that caused game card images to fail to be removed when requested.

* Updates to signalR architecture. Improve spinner readability.

* Only respond to sync start events for the current game in the session start controls.

* Finalize SignalR GameHub implementation

* Audit fix

* Update reset team endpoint paylod

* All hidden challenge specs.

* Bump katex from 0.16.4 to 0.16.10

Bumps [katex](https://github.com/KaTeX/KaTeX) from 0.16.4 to 0.16.10.
- [Release notes](https://github.com/KaTeX/KaTeX/releases)
- [Changelog](https://github.com/KaTeX/KaTeX/blob/main/CHANGELOG.md)
- [Commits](KaTeX/KaTeX@v0.16.4...v0.16.10)

---
updated-dependencies:
- dependency-name: katex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>

* Add player readiness counts to external game deploy admin. Resolves GBAPI #405.

* Added simple filtering/search to active team/challenge modals

* Fix various unenroll/reset session bugs. Readying/unreading a player from Players now applies the condition to their entire team.

* Clean up button text

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
sei-bstein and dependabot[bot] authored Apr 1, 2024
1 parent c38064d commit 6af1b29
Show file tree
Hide file tree
Showing 69 changed files with 1,014 additions and 784 deletions.
617 changes: 282 additions & 335 deletions package-lock.json

Large diffs are not rendered by default.

46 changes: 46 additions & 0 deletions patch-it
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
diff --git a/projects/gameboard-ui/src/app/components/gameboard-signalr-hubs/gameboard-signalr-hubs.component.ts b/projects/gameboard-ui/src/app/components/gameboard-signalr-hubs/gameboard-signalr-hubs.component.ts
index 4a62c8e6..90239460 100644
--- a/projects/gameboard-ui/src/app/components/gameboard-signalr-hubs/gameboard-signalr-hubs.component.ts
+++ b/projects/gameboard-ui/src/app/components/gameboard-signalr-hubs/gameboard-signalr-hubs.component.ts
@@ -73,6 +73,7 @@ export class GameboardSignalRHubsComponent implements OnDestroy {

// connect to the hubs
await this.gameHub.connect();
+ await this.supportHub.connect();
await this.userHub.connect();

// listen for interesting events to log
@@ -93,15 +94,10 @@ export class GameboardSignalRHubsComponent implements OnDestroy {
this.log("[GB UserHub]: Hub state is", userHubState);
this.userHubStatusLightState = this.hubStateToStatusLightState(userHubState);
this.userHubTooltip = `UserHub: ${userHubState}`;
- })
- );
+ }),

- // join the support hub (which everyone uses to get ticket updates)
- if (u.isAdmin || u.isSupport) {
- await this.supportHub.connect();
- await this.supportHub.joinStaffGroup();
- this.unsub.add(this.supportHub.hubState$.subscribe(supportHubState => this.supportHubStatusLightState = this.hubStateToStatusLightState(supportHubState)));
- }
+ this.supportHub.hubState$.subscribe(supportHubState => this.supportHubStatusLightState = this.hubStateToStatusLightState(supportHubState))
+ );
}
}

diff --git a/projects/gameboard-ui/src/app/services/signalR/support-hub.service.ts b/projects/gameboard-ui/src/app/services/signalR/support-hub.service.ts
index 67ba3dcb..c05474ae 100644
--- a/projects/gameboard-ui/src/app/services/signalR/support-hub.service.ts
+++ b/projects/gameboard-ui/src/app/services/signalR/support-hub.service.ts
@@ -41,10 +41,6 @@ export class SupportHubService {
);
}

- public async joinStaffGroup() {
- await this._signalRService.sendMessage("joinStaffGroup");
- }
-
private handleTicketClosed(ev: SupportHubEvent<TicketClosedEvent>) {
this.logService.logInfo("[GB Support Hub Staff Group]: Ticket Closed", ev);

Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,16 @@ <h4 class="mb-2 px-3">Other tools</h4>
<app-confirm-button btnClass="btn btn-sm btn-danger" *ngIf="canUnenroll"
(confirm)="onUnenrollRequest.emit(team.teamId)">Unenroll</app-confirm-button>
<app-confirm-button btnClass="btn btn-sm btn-danger mr-2" *ngIf="!canUnenroll"
(confirm)="onResetSessionRequest.emit({ player, unenrollTeam: false })">
(confirm)="onResetSessionRequest.emit({ player, resetType: 'preserveChallenges' })">
Reset Session (Preserve Challenges)
</app-confirm-button>
<app-confirm-button btnClass="btn btn-sm btn-danger mr-2" *ngIf="!canUnenroll"
(confirm)="onResetSessionRequest.emit({ player, resetType: 'archiveChallenges' })">
Reset Session
</app-confirm-button>
<app-confirm-button btnClass="btn btn-sm btn-danger" *ngIf="!canUnenroll"
(confirm)="onResetSessionRequest.emit({ player, unenrollTeam: true })">Reset Session &amp;
(confirm)="onResetSessionRequest.emit({ player, resetType: 'unenrollAndArchiveChallenges' })">Reset Session
&amp;
Unenroll</app-confirm-button>
</div>
</div>
Expand Down
4 changes: 4 additions & 0 deletions projects/gameboard-ui/src/app/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { SiteOverviewStatsComponent } from './components/site-overview-stats/sit
import { SpecBrowserComponent } from './spec-browser/spec-browser.component';
import { SponsorBrowserComponent } from './sponsor-browser/sponsor-browser.component';
import { SupportReportLegacyComponent } from './support-report-legacy/support-report-legacy.component';
import { SyncStartTeamPlayerReadyCountPipe } from './pipes/sync-start-team-player-ready-count.pipe';
import { SystemNotificationsModule } from '@/system-notifications/system-notifications.module';
import { TeamAdminContextMenuComponent } from './components/team-admin-context-menu/team-admin-context-menu.component';
import { TeamObserverComponent } from './team-observer/team-observer.component';
Expand All @@ -62,6 +63,7 @@ import { ExtendTeamsModalComponent } from './components/extend-teams-modal/exten
import { ActiveTeamsModalComponent } from './components/active-teams-modal/active-teams-modal.component';
import { AdminEnrollTeamModalComponent } from './components/admin-enroll-team-modal/admin-enroll-team-modal.component';
import { GameYamlImportModalComponent } from './components/game-yaml-import-modal/game-yaml-import-modal.component';
import { SyncStartGameStateDescriptionPipe } from './pipes/sync-start-game-state-description.pipe';

@NgModule({
declarations: [
Expand Down Expand Up @@ -113,6 +115,8 @@ import { GameYamlImportModalComponent } from './components/game-yaml-import-moda
ActiveTeamsModalComponent,
AdminEnrollTeamModalComponent,
GameYamlImportModalComponent,
SyncStartTeamPlayerReadyCountPipe,
SyncStartGameStateDescriptionPipe,
],
imports: [
CommonModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,69 +9,94 @@ <h2 class="modal-title">Active Challenges: {{ playerMode | titlecase }}</h2>

<div class="modal-body" *ngIf="!isWorking; else loading">
<ng-container *ngIf="specs?.length; else noChallenges">
<div *ngFor="let spec of specs" class="spec-container">
<h3>{{ spec.name }}</h3>
<h4 class="game-link">
<a target="_blank" [routerLink]="['game/' + spec.game.id]">
{{ spec.game.name }}
</a>
</h4>
<div class="search container">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">
<fa-icon [icon]="fa.search"></fa-icon>
</span>
</div>
<input type="text" class="form-control"
placeholder="Search by challenge ID/name, challenge spec ID, or team ID" appAutofocus
aria-label="Team Search" (input)="handleSearchInput(searchInput.value || '')" #searchInput>
</div>
</div>

<ul class="d-flex flex-wrap">
<li *ngFor="let challenge of spec.challenges" class="card challenge-card my-3 mr-3">
<div class="card-body">
<h5 class="overflow-ellipsis">
{{ challenge.team.name }}
</h5>
<button type="button" class="btn btn-link text-info" appCopyOnClick
tooltip="Copy this support code" placement="bottom">
{{ {id: challenge.id, tag: spec.tag } | toSupportCode }}
</button>
<div class="challenge-times mt-2">
<div class="start-time">
<span class="font-bold">Launched: </span>
<span>{{ challenge.startedAt | datetimeToDate | friendlyDateAndTime }}</span>
</div>
<div class="end-time">
<span class="font-bold">Session End: </span>
<span>{{ challenge.team.session.end | datetimeToDate | friendlyDateAndTime }}</span>
<ng-container *ngIf="matchingSpecs.length; else noMatchingChallenges">
<div *ngFor="let spec of matchingSpecs" class="spec-container">
<h3>{{ spec.name }}</h3>
<h4 class="game-link">
<a target="_blank" [routerLink]="['game/' + spec.game.id]">
{{ spec.game.name }}
</a>
</h4>

<ul class="d-flex flex-wrap">
<li *ngFor="let challenge of spec.challenges" class="card challenge-card my-3 mr-3">
<div class="card-body">
<h5 class="overflow-ellipsis">
{{ challenge.team.name }}
</h5>
<button type="button" class="btn btn-link text-info" appCopyOnClick
tooltip="Copy this support code" placement="bottom">
{{ {id: challenge.id, tag: spec.tag } | toSupportCode }}
</button>
<div class="challenge-times mt-2">
<div class="start-time">
<span class="font-bold">Launched: </span>
<span>{{ challenge.startedAt | datetimeToDate | friendlyDateAndTime }}</span>
</div>
<div class="end-time">
<span class="font-bold">Session End: </span>
<span>{{ challenge.team.session.end | datetimeToDate | friendlyDateAndTime
}}</span>
</div>
</div>
</div>
</div>
<div class="card-footer d-flex align-items-center px-3">
<div class="flex-grow-1">
<a [href]="'support/tickets?search=' + challenge.id | relativeToAbsoluteHref"
target="_blank" *ngIf="challenge.hasTickets" class="btn btn-warning"
tooltip="View open tickets for this challenge" placement="bottom">
<fa-icon [icon]="fa.ticket" size="lg"></fa-icon>

<div class="card-footer d-flex align-items-center px-3">
<div class="flex-grow-1">
<a [href]="'support/tickets?search=' + challenge.id | relativeToAbsoluteHref"
target="_blank" *ngIf="challenge.hasTickets" class="btn btn-warning"
tooltip="View open tickets for this challenge" placement="bottom">
<fa-icon [icon]="fa.ticket" size="lg"></fa-icon>
</a>
</div>

<button type="button" tooltip="Copy this challenge's ID" placement="bottom"
class="btn btn-info mr-2" [appCopyOnClick]="challenge.id">
<fa-icon [icon]="fa.copy"></fa-icon>
</button>

<a [href]="'admin/support?search=' + challenge.id | relativeToAbsoluteHref"
target="_blank" class="btn btn-info mr-2" tooltip="View this challenge's state"
placement="bottom">
<fa-icon [icon]="fa.barsStaggered" size="lg"></fa-icon>
</a>
</div>
<a [href]="'admin/support?search=' + challenge.id | relativeToAbsoluteHref" target="_blank"
class="btn btn-info mr-2" tooltip="View this challenge's state" placement="bottom">
<fa-icon [icon]="fa.barsStaggered" size="lg"></fa-icon>
</a>

<a [href]="'admin/registrar/' + spec.game.id + '?term=' + challenge.team.id | relativeToAbsoluteHref"
target="_blank" class="btn btn-info mr-2"
[tooltip]="'View this ' + (spec.game.isTeamGame ? 'team' : 'player') + '\'s session'"
placement="bottom">
<fa-icon [icon]="spec.game.isTeamGame ? fa.peopleGroup : fa.person" size="lg"></fa-icon>
</a>
<a [href]="'admin/registrar/' + spec.game.id + '?term=' + challenge.team.id | relativeToAbsoluteHref"
target="_blank" class="btn btn-info mr-2"
[tooltip]="'View this ' + (spec.game.isTeamGame ? 'team' : 'player') + '\'s session'"
placement="bottom">
<fa-icon [icon]="spec.game.isTeamGame ? fa.peopleGroup : fa.person"
size="lg"></fa-icon>
</a>

<a [href]="'admin/observer/challenges/' + spec.game.id + '?search=' + challenge.id | relativeToAbsoluteHref"
target="_blank" class="btn btn-info mr-2" tooltip="Observe this challenge"
placement="bottom">
<fa-icon [icon]="fa.eye" size="lg"></fa-icon>
</a>
<a [href]="'admin/observer/challenges/' + spec.game.id + '?search=' + challenge.id | relativeToAbsoluteHref"
target="_blank" class="btn btn-info mr-2" tooltip="Observe this challenge"
placement="bottom">
<fa-icon [icon]="fa.eye" size="lg"></fa-icon>
</a>

<a [href]="'game/' + spec.game.id | relativeToAbsoluteHref" target="_blank"
class="btn btn-info" tooltip="View this game" placement="bottom">
<fa-icon [icon]="fa.chessBoard" size="lg"></fa-icon>
</a>
</div>
</li>
</ul>
</div>
<a [href]="'game/' + spec.game.id | relativeToAbsoluteHref" target="_blank"
class="btn btn-info" tooltip="View this game" placement="bottom">
<fa-icon [icon]="fa.chessBoard" size="lg"></fa-icon>
</a>
</div>
</li>
</ul>
</div>
</ng-container>
</ng-container>
</div>

Expand All @@ -84,6 +109,10 @@ <h5 class="overflow-ellipsis">
<div class="text-center gray-text fs-11">There aren't any active challenges of this type right now.</div>
</ng-template>

<ng-template #noMatchingChallenges>
<div class="text-center gray-text fs-11">None of the active challenges match your search.</div>
</ng-template>

<ng-template #loading>
<app-spinner></app-spinner>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { PlayerMode } from '@/api/player-models';
import { AppActiveChallengeSpec } from '@/api/admin.models';
import { AdminService } from '@/api/admin.service';
import { ModalConfirmService } from '@/services/modal-confirm.service';
import { RouterService } from '@/services/router.service';

@Component({
selector: 'app-active-challenges-modal',
Expand All @@ -19,12 +18,13 @@ export class ActiveChallengesModalComponent implements OnInit {
protected fa = fa;
protected isPracticeMode = false;
protected isWorking = false;

protected matchingSpecs: AppActiveChallengeSpec[] = [];
protected specs: AppActiveChallengeSpec[] = [];

constructor(
private adminService: AdminService,
private modalService: ModalConfirmService,
private routerService: RouterService) { }
private modalService: ModalConfirmService) { }

async ngOnInit(): Promise<void> {
if (!this.playerMode)
Expand All @@ -33,6 +33,22 @@ export class ActiveChallengesModalComponent implements OnInit {
await this.load(this.playerMode);
}

protected handleSearchInput(text: string) {
if (!text) {
this.matchingSpecs = this.specs;
return;
}

text = text.toLowerCase();

this.matchingSpecs = this.specs.filter(s =>
s.id.toLowerCase().indexOf(text) >= 0 ||
s.name.toLowerCase().indexOf(text) >= 0 ||
s.challenges.some(c => c.team.id.indexOf(text) >= 0) ||
s.challenges.some(c => c.id.indexOf(text) >= 0)
);
}

protected close() {
this.modalService.hide();
}
Expand All @@ -44,6 +60,7 @@ export class ActiveChallengesModalComponent implements OnInit {
try {
this.isWorking = true;
const response = await firstValueFrom(this.adminService.getActiveChallenges(playerMode));
this.matchingSpecs = response.specs;
this.specs = response.specs;
this.isWorking = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,21 @@ <h2 class="modal-title">Active Competitive Teams &amp; Players</h2>

<div class="modal-body" *ngIf="!isWorking; else loading">
<ng-container *ngIf="teams.length; else noTeams">
<div class="teams-container">
<ul class="d-flex flex-wrap">
<li *ngFor="let team of teams" class="card team-card my-3 mr-3">
<div class="search-container">
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">
<fa-icon [icon]="fa.search"></fa-icon>
</span>
</div>
<input type="text" class="form-control" placeholder="Search by team name or ID" appAutofocus
aria-label="Team Search" (input)="handleSearchInput(searchInput.value || '')" #searchInput>
</div>
</div>

<div class=" teams-container">
<ul *ngIf="teams.length && matchingSearchTeams.length; else noMatchingTeams" class="d-flex flex-wrap">
<li *ngFor="let team of matchingSearchTeams" class="card team-card my-3 mr-3">
<div class="card-body">
<h5 class="overflow-ellipsis">
{{ team.name }}
Expand Down Expand Up @@ -49,6 +61,11 @@ <h6 class="game-link m-0">
<fa-icon [icon]="fa.ticket" size="lg"></fa-icon>
</a>
</div>
<button type="button" [appCopyOnClick]="team.id"
[tooltip]="'Copy this ' + (team.game.isTeamGame ? 'team' : 'player') + '\'s team ID'"
placement="bottom" class="btn btn-info mr-2">
<fa-icon [icon]="fa.copy" size="lg"></fa-icon>
</button>
<a [href]="'admin/support?search=' + team.id | relativeToAbsoluteHref" target="_blank"
class="btn btn-info mr-2"
[tooltip]="'View challenge states for this ' + (team.game.isTeamGame ? 'team' : 'player')"
Expand Down Expand Up @@ -90,6 +107,10 @@ <h6 class="game-link m-0">
<div class="text-center gray-text fs-11">There aren't any active teams right now.</div>
</ng-template>

<ng-template #noMatchingTeams>
<div class="text-center gray-text fs-11">There aren't any active teams which match your search.</div>
</ng-template>

<ng-template #loading>
<app-spinner></app-spinner>
</ng-template>
Loading

0 comments on commit 6af1b29

Please sign in to comment.