Skip to content

Commit

Permalink
v3.25.7 (#220)
Browse files Browse the repository at this point in the history
* Retheme announce button

* Misc cleanup and styling on Live view (and fixed broken links)

* Align the cert picker with the feedback template picker

* Don't center .gameboard-table column headers by default

* Styling for report multiselect

* Fix visual bug in team detail in game center

* Add context menu to practice tab in game center

* Bug fix and live refresh timer

* Better error handling for the ticket form. ID viewer on game center -> teams. Handle line breaks in tickets better
  • Loading branch information
sei-bstein authored Jan 10, 2025
1 parent 0189a81 commit 90c91a4
Show file tree
Hide file tree
Showing 26 changed files with 270 additions and 98 deletions.
2 changes: 2 additions & 0 deletions projects/gameboard-ui/src/app/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ import { FeedbackTemplatePickerComponent } from "../feedback/components/feedback
import { UserPickerComponent } from '@/standalone/users/user-picker/user-picker.component';
import { CertificateTemplatePickerComponent } from '@/certificates/components/certificate-template-picker/certificate-template-picker.component';
import { CertificatePreviewerComponent } from '@/certificates/components/certificate-previewer/certificate-previewer.component';
import { GameCenterPracticeTeamContextMenuComponent } from './components/game-center/game-center-practice-team-context-menu/game-center-practice-team-context-menu.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -223,6 +224,7 @@ import { CertificatePreviewerComponent } from '@/certificates/components/certifi
SystemNotificationsModule,
// standalones
ErrorDivComponent,
GameCenterPracticeTeamContextMenuComponent,
GameInfoBubblesComponent,
IfHasPermissionDirective,
SafeUrlPipe,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
[(ngModel)]="message">
</textarea>
<div class="input-group-append">
<button class="btn btn-outline-info" (click)="announce()" [disabled]="!message">
<button class="btn btn-success" (click)="announce()" [disabled]="!message">
<fa-icon [icon]="faSend"></fa-icon>
<span>Announce</span>
</button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,44 +55,42 @@ <h5 class="overflow-ellipsis">
</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>
</a>
</div>
<div class="card-footer d-flex justify-content-end">
<a [href]="'support/tickets?search=' + challenge.id | relativeToAbsoluteHref"
target="_blank" *ngIf="challenge.hasTickets" class="btn btn-sm btn-warning mr-2"
tooltip="View open tickets for this challenge" placement="bottom">
<fa-icon [icon]="fa.ticket"></fa-icon>
</a>

<button type="button" tooltip="Copy this challenge's ID" placement="bottom"
class="btn btn-success mr-2" [appCopyOnClick]="challenge.id">
class="btn btn-sm btn-success 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-success mr-2" tooltip="View this challenge's state"
placement="bottom">
<fa-icon [icon]="fa.barsStaggered" size="lg"></fa-icon>
target="_blank" class="btn btn-sm btn-success mr-2"
tooltip="View this challenge's state" placement="bottom">
<fa-icon [icon]="fa.barsStaggered"></fa-icon>
</a>

<a [routerLink]="['admin', 'game', spec.game.id, 'teams']"
[queryParams]="{ search: challenge.team.id }" target="_blank"
class="btn btn-success mr-2"
class="btn btn-sm btn-success 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>
<fa-icon [icon]="spec.game.isTeamGame ? fa.peopleGroup : fa.person"></fa-icon>
</a>

<a [routerLink]="['admin', 'game', spec.game.id, 'observe']"
[queryParams]=" { challengeId: challenge.id }" target="_blank"
class="btn btn-success mr-2" tooltip="Observe this challenge" placement="bottom">
<fa-icon [icon]="fa.eye" size="lg"></fa-icon>
class="btn btn-sm btn-success mr-2" tooltip="Observe this challenge"
placement="bottom">
<fa-icon [icon]="fa.eye"></fa-icon>
</a>

<a [href]="'game/' + spec.game.id | relativeToAbsoluteHref" target="_blank"
class="btn btn-success" tooltip="View this game" placement="bottom">
<fa-icon [icon]="fa.chessBoard" size="lg"></fa-icon>
class="btn btn-sm btn-success" tooltip="View this game" placement="bottom">
<fa-icon [icon]="fa.chessBoard"></fa-icon>
</a>
</div>
</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { fa } from "@/services/font-awesome.service";
import { firstValueFrom } from 'rxjs';
import { fa } from "@/services/font-awesome.service";
import { PlayerMode } from '@/api/player-models';
import { AppActiveChallengeSpec } from '@/api/admin.models';
import { AdminService } from '@/api/admin.service';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,44 +52,44 @@ <h6 class="game-link m-0">
</div>
</div>
</div>
<div class="card-footer d-flex align-items-center">
<div class="flex-grow-1">
<a [href]="'support/tickets?search=' + team.id" target="_blank" *ngIf="team.hasTickets"
class="btn btn-warning"
[tooltip]="'View open tickets for this ' + (team.game.isTeamGame ? 'team' : 'player')"
placement="bottom">
<fa-icon [icon]="fa.ticket" size="lg"></fa-icon>
</a>
</div>
<div class="card-footer d-flex align-items-stretch justify-content-end">
<a [href]="'support/tickets?search=' + team.id" target="_blank" *ngIf="team.hasTickets"
class="btn btn-sm btn-warning mr-2"
[tooltip]="'View open tickets for this ' + (team.game.isTeamGame ? 'team' : 'player')"
placement="bottom">
<fa-icon [icon]="fa.ticket"></fa-icon>
</a>

<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>
placement="bottom" class="btn btn-sm btn-success mr-2">
<fa-icon [icon]="fa.copy"></fa-icon>
</button>

<a [href]="'admin/support?search=' + team.id | relativeToAbsoluteHref" target="_blank"
class="btn btn-info mr-2"
class="btn btn-sm btn-success mr-2"
[tooltip]="'View challenge states for this ' + (team.game.isTeamGame ? 'team' : 'player')"
placement="bottom">
<fa-icon [icon]="fa.barsStaggered" size="lg"></fa-icon>
<fa-icon [icon]="fa.barsStaggered"></fa-icon>
</a>

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

<a [href]="'admin/observer/teams/' + team.game.id + '?search=' + team.id | relativeToAbsoluteHref"
target="_blank" class="btn btn-info mr-2"
<a [routerLink]="['admin', 'game', team.game.id, 'observe']"
[queryParams]=" { teamId: team.id }" target="_blank" class="btn btn-sm btn-success mr-2"
[tooltip]="'Observe this ' + (team.game.isTeamGame ? 'team' : 'player')"
placement="bottom">
<fa-icon [icon]="fa.eye" size="lg"></fa-icon>
<fa-icon [icon]="fa.eye"></fa-icon>
</a>

<a [href]="'game/' + team.game.id |relativeToAbsoluteHref" target="_blank"
class="btn btn-info" tooltip="View this game" placement="bottom">
<fa-icon [icon]="fa.chessBoard" size="lg"></fa-icon>
class="btn btn-sm btn-success" tooltip="View this game" placement="bottom">
<fa-icon [icon]="fa.chessBoard"></fa-icon>
</a>
</div>
</li>
Expand All @@ -99,7 +99,7 @@ <h6 class="game-link m-0">
</div>

<div class="modal-footer">
<button type="button" class="btn btn-info" (click)="close()">OK</button>
<button type="button" class="btn btn-success" (click)="close()">OK</button>
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.team-card {
flex-basis: 30%;
}

input[type="button"] {
appearance: none !important;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Component, OnInit } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { fa } from '@/services/font-awesome.service';
import { AppActiveTeam } from '@/api/admin.models';
import { ModalConfirmService } from '@/services/modal-confirm.service';
import { AdminService } from '@/api/admin.service';
import { firstValueFrom } from 'rxjs';

@Component({
selector: 'app-active-teams-modal',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { GameHubService } from '@/services/signalR/game-hub.service';
import { SupportHubService } from '@/services/signalR/support-hub.service';
import { Component } from '@angular/core';
import { HubConnectionState } from '@microsoft/signalr';
import { Observable } from 'rxjs';
import { GameHubService } from '@/services/signalR/game-hub.service';
import { SupportHubService } from '@/services/signalR/support-hub.service';

@Component({
selector: 'app-admin-overview',
templateUrl: './admin-overview.component.html',
styleUrls: ['./admin-overview.component.scss']
templateUrl: './admin-overview.component.html'
})
export class AdminOverviewComponent {
protected gameHubState$: Observable<HubConnectionState>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<ng-container *ngIf="user">
<div class="btn-group" dropdown>
<button [id]="'game-center-practice-team-context-menu-button-{{user.id}}' + user.id" dropdownToggle
type="button" class="btn ctx-menu-button rounded-circle" aria-controls="dropdown-basic">
<fa-icon [icon]="fa.ellipsisVertical" size="2x"></fa-icon>
</button>
<ul id="game-center-practice-team-context-menu-{{user.id}}" *dropdownMenu class="dropdown-menu" role="menu"
aria-labelledby="button-basic">
<li role="menuitem">
<button class="dropdown-item btn" (click)="teamDetailClick.next(user)">More</button>
</li>

<ng-container *ngIf="user.activeChallenge">
<li class="divider dropdown-divider"></li>

<li role="menuitem">
<button class="dropdown-item btn btn-danger" (click)="handleResetSessionClick()">
Reset Session
</button>
</li>
</ng-container>
</ul>
</div>
</ng-container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { fa } from "@/services/font-awesome.service";
import { GameCenterPracticeContextUser } from '../game-center.models';
import { CoreModule } from '@/core/core.module';
import { SimpleEntity } from '@/api/models';
import { PracticeService } from '@/services/practice.service';
import { TeamService } from '@/api/team.service';
import { ToastService } from '@/utility/services/toast.service';
import { ModalConfirmService } from '@/services/modal-confirm.service';

@Component({
selector: 'app-game-center-practice-team-context-menu',
standalone: true,
imports: [
CommonModule,
CoreModule,
],
templateUrl: './game-center-practice-team-context-menu.component.html',
styleUrls: ['./game-center-practice-team-context-menu.component.scss']
})
export class GameCenterPracticeTeamContextMenuComponent {
@Input() user?: GameCenterPracticeContextUser;
@Input() game?: SimpleEntity;
@Output() sessionReset = new EventEmitter<GameCenterPracticeContextUser>();
@Output() teamDetailClick = new EventEmitter<GameCenterPracticeContextUser>();

private practiceService = inject(PracticeService);
private modalService = inject(ModalConfirmService);
private teamService = inject(TeamService);
private toastService = inject(ToastService);

protected fa = fa;

protected handleResetSessionClick() {
if (!this.user?.activeChallenge) {
throw new Error("User doesn't have an active practice challenge.");
}

this.modalService.openConfirm({
title: "Reset Practice Session?",
subtitle: this.user.name,
bodyContent: `Reset ${this.user.name}'s practice session? All of their progress in the current session will be erased. **You can't undo this**.`,
renderBodyAsMarkdown: true,
onConfirm: async () => {
const session = await this.practiceService.getSession();
if (session) {
try {
await this.teamService.endSession({ teamId: session.teamId });
}
catch (err: any) {
this.toastService.showMessage(`Error resetting session: ${err}`);
}
}

if (this.user) {
this.toastService.showMessage(`User **${this.user.name}**'s practice session has been reset.`);
this.sessionReset.emit(this.user);
}
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
<input type="text" minlength="2" placeholder="Search players" [(ngModel)]="filterSettings.searchTerm"
(input)="searchInput$.next(searchInput.value)" class="form-control d-block flex-grow-1" #searchInput>

<select class="form-control ml-2" [(ngModel)]="filterSettings.sessionStatus" (change)="load()">
<option [ngValue]="undefined" (change)="load()">[Any status]</option>
<select class="form-control ml-2" [ngModel]="filterSettings.sessionStatus"
(ngModelChange)="handleSessionStatusChange($event)">
<option [ngValue]="undefined">[Any status]</option>
<option value="playing">Playing</option>
<option value="notPlaying">Not playing</option>
</select>

<select [(ngModel)]="filterSettings.sort" (change)="load()" class="form-control ml-2">
<select [ngModel]="filterSettings.sort" (ngModelChange)="handleSortChange($event)" class="form-control ml-2">
<option value="attemptCount">Sort by attempt count</option>
<option value="name">Sort by name</option>
</select>
Expand Down Expand Up @@ -38,8 +39,9 @@
</div>
</div>
<div contextMenu>
<button type="button" class="btn btn-success"
(click)="handleUserDetailClick(user)">More</button>
<app-game-center-practice-team-context-menu [user]="user" [game]="ctx?.game"
(sessionReset)="handleSessionReset($event)"
(teamDetailClick)="handleUserDetailClick($event)"></app-game-center-practice-team-context-menu>
</div>
</app-team-list-card>
</li>
Expand Down
Loading

0 comments on commit 90c91a4

Please sign in to comment.