Select an image for the game card shown in the public-facing portion of the app. For best results, use an
image with an aspect ratio of 1:1.44 (e.g. 750x1080).
-
-
-
- Results limited to {{search.take}}. Refine search
- term if necessary.
+
+ Results limited to {{search.take}}. Refine search term if necessary.
+
count: {{players.length}}
-
+
{{player.approvedName}}
diff --git a/projects/gameboard-ui/src/app/admin/player-names/player-names.component.ts b/projects/gameboard-ui/src/app/admin/player-names/player-names.component.ts
index bf97dfd7..dffe8d25 100644
--- a/projects/gameboard-ui/src/app/admin/player-names/player-names.component.ts
+++ b/projects/gameboard-ui/src/app/admin/player-names/player-names.component.ts
@@ -1,9 +1,9 @@
// Copyright 2021 Carnegie Mellon University. All Rights Reserved.
// Released under a MIT (SEI)-style license. See LICENSE.md in the project root for license information.
-import { Component, OnInit } from '@angular/core';
+import { Component } from '@angular/core';
import { faSearch, faFilter, faCheck, faArrowLeft, faTimes, faUndo } from '@fortawesome/free-solid-svg-icons';
-import { BehaviorSubject, combineLatest, interval, Observable, scheduled, timer } from 'rxjs';
+import { BehaviorSubject, combineLatest, firstValueFrom, Observable, timer } from 'rxjs';
import { debounceTime, switchMap, tap } from 'rxjs/operators';
import { Player, PlayerSearch } from '../../api/player-models';
import { PlayerService } from '../../api/player.service';
@@ -13,7 +13,7 @@ import { PlayerService } from '../../api/player.service';
templateUrl: './player-names.component.html',
styleUrls: ['./player-names.component.scss']
})
-export class PlayerNamesComponent implements OnInit {
+export class PlayerNamesComponent {
refresh$ = new BehaviorSubject(true);
players$: Observable;
source: Player[] = [];
@@ -51,9 +51,6 @@ export class PlayerNamesComponent implements OnInit {
}
- ngOnInit(): void {
- }
-
toggleFilter(role: string): void {
this.filter = this.filter !== role ? role : '';
if (!!this.filter) {
@@ -69,8 +66,13 @@ export class PlayerNamesComponent implements OnInit {
this.refresh$.next(true);
}
- update(model: Player): void {
- this.api.update(model).subscribe();
+ async update(model: Player): Promise {
+ await firstValueFrom(this.api.update({
+ id: model.id,
+ name: model.name,
+ approvedName: model.approvedName,
+ nameStatus: model.nameStatus
+ }));
}
approveName(model: Player): void {
diff --git a/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.html b/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.html
index ee4f8f28..feda6370 100644
--- a/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.html
+++ b/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.html
@@ -130,7 +130,8 @@
Players — {{ctx.game.name}}
-
diff --git a/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.ts b/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.ts
index 6b6682f1..0a3b7097 100644
--- a/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.ts
+++ b/projects/gameboard-ui/src/app/admin/player-registrar/player-registrar.component.ts
@@ -4,7 +4,7 @@
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { BsModalService } from 'ngx-bootstrap/modal';
-import { asyncScheduler, BehaviorSubject, combineLatest, firstValueFrom, iif, interval, Observable, of, scheduled, timer } from 'rxjs';
+import { asyncScheduler, BehaviorSubject, combineLatest, firstValueFrom, interval, Observable, scheduled, timer } from 'rxjs';
import { debounceTime, filter, first, map, mergeAll, switchMap, tap } from 'rxjs/operators';
import { BoardService } from '../../api/board.service';
import { Game } from '../../api/game-models';
diff --git a/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.html b/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.html
index 2885f97e..1ddfe76e 100644
--- a/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.html
+++ b/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.html
@@ -27,12 +27,14 @@
Board Reports
- Export Board Report to CSV
+ Export
+ Board Report to CSV
- Export Sponsor Report to CSV
+ Export Sponsor Report to
+ CSV
@@ -61,7 +63,8 @@
Board: {{g.gameName}}
Player Count
-
{{s.name}}
+
{{s.name}}
{{s.count}}
@@ -75,7 +78,9 @@
All Sponsors
User Count
-
{{s.name}}
+
{{s.name}}
+
{{s.count}}
diff --git a/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.ts b/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.ts
index 0bcf6785..3a683c38 100644
--- a/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.ts
+++ b/projects/gameboard-ui/src/app/admin/player-sponsor-report/player-sponsor-report.component.ts
@@ -1,8 +1,7 @@
// Copyright 2021 Carnegie Mellon University. All Rights Reserved.
// Released under a MIT (SEI)-style license. See LICENSE.md in the project root for license information.
-import { Component, OnInit, ViewChild } from '@angular/core';
-import { PlatformLocation } from '@angular/common';
+import { Component, ViewChild } from '@angular/core';
import { faArrowLeft } from '@fortawesome/free-solid-svg-icons';
import { FormGroup, NgForm } from '@angular/forms';
import { Search } from '../../api/models';
@@ -17,7 +16,7 @@ import { SponsorService } from '../../api/sponsor.service';
templateUrl: './player-sponsor-report.component.html',
styleUrls: ['./player-sponsor-report.component.scss']
})
-export class PlayerSponsorReportComponent implements OnInit {
+export class PlayerSponsorReportComponent {
@ViewChild(NgForm) form!: FormGroup;
gameSponsorReport?: GameSponsorReport;
sponsors?: SponsorReport;
@@ -31,8 +30,7 @@ export class PlayerSponsorReportComponent implements OnInit {
constructor(
private api: ReportService,
private gameService: GameService,
- private sponsorService: SponsorService,
- private platform: PlatformLocation
+ private sponsorService: SponsorService
) {
this.gameService.list(this.search).subscribe(
r => {
@@ -42,7 +40,6 @@ export class PlayerSponsorReportComponent implements OnInit {
this.api.gameSponsorReport(this.currentGame.id).subscribe(
r => {
- r.stats.forEach(gss => gss.stats.forEach(ss => ss.logo = sponsorService.getLogoUrl(ss.logo)));
this.gameSponsorReport = r;
}
);
@@ -53,15 +50,11 @@ export class PlayerSponsorReportComponent implements OnInit {
this.api.sponsorReport().subscribe(
r => {
this.sponsors = r;
- r.stats.forEach(ss => ss.logo = sponsorService.getLogoUrl(ss.logo));
this.sponsorStats = r.stats;
}
);
}
- ngOnInit(): void {
- }
-
updateGame(id: string) {
if (this.games) {
this.currentGame = this.games.find(g => g.id == id);
@@ -69,7 +62,6 @@ export class PlayerSponsorReportComponent implements OnInit {
if (this.currentGame) {
this.api.gameSponsorReport(this.currentGame.id).subscribe(
r => {
- r.stats.forEach(gss => gss.stats.forEach(ss => ss.logo = this.sponsorService.getLogoUrl(ss.logo)));
this.gameSponsorReport = r;
}
);
diff --git a/projects/gameboard-ui/src/app/admin/practice/practice-challenges/practice-challenges.component.html b/projects/gameboard-ui/src/app/admin/practice/practice-challenges/practice-challenges.component.html
deleted file mode 100644
index 614768ce..00000000
--- a/projects/gameboard-ui/src/app/admin/practice/practice-challenges/practice-challenges.component.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
A coolified view of active practice challenges is coming soon!
- This text appears on the practice page to introduce players to playing in the Practice Area. Edit it below to
- customize it
- to your needs.
+ This text appears on the practice page to introduce players to playing in the Practice Area. Edit it below
+ to customize it to your needs.
-
-
Certificate Template
+
+
Suggested searches
+
+
+ These search terms will appear on the homepage of the Practice Area, just below the greeting. You can use
+ these to direct players to useful or interesting subsets of the available practice challenges.
+
+
+
+ NOTE: Enter one suggested search per line.
+
+
+
+
Certificate Template
Players are able to save certificates in PDF format for each practice challenge they fully complete. Use
- this field
- to customize the appearance of these certificates.
+ this field to customize the appearance of these certificates.
-
-
Session Limits
+
+
Session Limits
You can use the controls below to set limits on practice sessions, including how many can be active at once
how long they are by default, and the max length that a player can play in a single practice session.
diff --git a/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.scss b/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.scss
index 3ee8be9a..4e33c6de 100644
--- a/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.scss
+++ b/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.scss
@@ -1,3 +1,8 @@
.form-group {
flex: 1 1 50%;
}
+
+.settings-section {
+ margin-top: 3rem;
+ margin-bottom: 3rem;
+}
diff --git a/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.ts b/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.ts
index 77c32b7c..96c7bb4c 100644
--- a/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.ts
+++ b/projects/gameboard-ui/src/app/admin/practice/practice-settings/practice-settings.component.ts
@@ -20,22 +20,18 @@ export class PracticeSettingsComponent implements OnInit {
ctx: PracticeSettingsContext | null = null;
private _startUpdate$ = new Subject();
+ protected suggestedSearchesLineDelimited = "";
+
protected certificateHtmlPlaceholder = [
"Enter an HTML template here which will be used to create certificates for the Practice Area. For each challenge they fully solve, players will be able to print a PDF of this certificate.",
"You can use several variables to display information about the player's performance on the challenge by including these \"magic strings\" in your template.They include: ",
`
- {{playerName}} - The player's approved username
-
- {{score}} - The player's score on the challenge
-
- {{date}} - The date the player completed the challenge
-
- {{challengeName}} - The name of the challenge
-
- {{season}} - The season the challenge was originally played in competitive mode
-
- {{track}} - The track upon which the challenge was originally placed in competitive mode
-
- {{time}} - The amount of time the player spent solving the challenge
`
].join("\n\n");
@@ -56,6 +52,8 @@ export class PracticeSettingsComponent implements OnInit {
introTextPlaceholder: this.markdownHelpers.getMarkdownPlaceholderHelp(`Enter your "intro to the Practice Area" text here!`),
settings: await firstValueFrom(this.practiceService.getSettings())
};
+
+ this.suggestedSearchesLineDelimited = this.ctx.settings.suggestedSearches.join("\n");
}
handleShowCertificateTemplateHelp() {
@@ -68,6 +66,7 @@ export class PracticeSettingsComponent implements OnInit {
}
handleSettingsChanged(settings: PracticeModeSettings) {
+ settings.suggestedSearches = !this.suggestedSearchesLineDelimited ? [] : this.suggestedSearchesLineDelimited.split("\n").map(entry => entry.trim());
this._startUpdate$.next(settings);
}
}
diff --git a/projects/gameboard-ui/src/app/admin/sponsor-browser/sponsor-browser.component.html b/projects/gameboard-ui/src/app/admin/sponsor-browser/sponsor-browser.component.html
index 915d99f2..3595a528 100644
--- a/projects/gameboard-ui/src/app/admin/sponsor-browser/sponsor-browser.component.html
+++ b/projects/gameboard-ui/src/app/admin/sponsor-browser/sponsor-browser.component.html
@@ -1,40 +1,30 @@
-
-
-
-
+
-
Sponsors
+
+
+
Create a New Sponsor
+
+
-
- or drag sponsor images here. (Filename should be the sponsor key.)
-
- Acceptable file types: .png, .jpeg, .jpg, .gif, .webp, .svg
-
+
+
-
-
-
diff --git a/projects/gameboard-ui/src/app/game/gameboard-page/gameboard-page.component.ts b/projects/gameboard-ui/src/app/game/gameboard-page/gameboard-page.component.ts
index a1db2d9b..b8295098 100644
--- a/projects/gameboard-ui/src/app/game/gameboard-page/gameboard-page.component.ts
+++ b/projects/gameboard-ui/src/app/game/gameboard-page/gameboard-page.component.ts
@@ -1,7 +1,7 @@
// Copyright 2021 Carnegie Mellon University. All Rights Reserved.
// Released under a MIT (SEI)-style license. See LICENSE.md in the project root for license information.
-import { Component, OnDestroy } from '@angular/core';
+import { Component, OnDestroy, ViewChild } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, Router } from '@angular/router';
import { faArrowLeft, faBolt, faExclamationTriangle, faTrash, faTv } from '@fortawesome/free-solid-svg-icons';
@@ -17,6 +17,7 @@ import { GameboardPerformanceSummaryViewModel } from '../../core/components/game
import { BrowserService } from '@/services/browser.service';
import { HttpErrorResponse } from '@angular/common/http';
import { ApiError } from '@/api/models';
+import { ConfirmButtonComponent } from '@/core/components/confirm-button/confirm-button.component';
@Component({
selector: 'app-gameboard-page',
@@ -48,6 +49,8 @@ export class GameboardPageComponent implements OnDestroy {
cid = '';
performanceSummaryViewModel?: GameboardPerformanceSummaryViewModel;
+ @ViewChild("startChallengeConfirmButton") protected startChallengeConfirmButton?: ConfirmButtonComponent;
+
constructor(
route: ActivatedRoute,
title: Title,
@@ -129,6 +132,8 @@ export class GameboardPageComponent implements OnDestroy {
map(c => this.syncOne({ ...c, specId: s.id }))
)
),
+ // don't persist the "confirming" state if they switch challenges (#178)
+ tap(c => this.startChallengeConfirmButton?.stopConfirming()),
tap(s => this.selected = s)
);
diff --git a/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.html b/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.html
index 6e023838..1b1698c7 100644
--- a/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.html
+++ b/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.html
@@ -16,17 +16,17 @@
-
+
Ready to play? Before you do, you'll need to visit your
- profile to...
+ profile to...
Make sure you've entered your name
-
Select your sponsor
+
Select your sponsor
-
+
@@ -48,39 +48,40 @@
By enrolling in {{ctx.game.name}}, you are accepting the following terms.
-
-
-
-
-
-
-
- Enroll
-
-
-
-
-
- Admin Enroll
-
-
+
+
+
+
+
+
+ Enroll
+
+
-
-
+
+
+
+ Admin Enroll
+
+
+
+
+
-
+
- Your name is pending approval from an administrator. Return later or select 'Update' to see if it's been
- approved.
+ Your name is pending approval from an administrator. Return later or select 'Update' to see if it's
+ been approved.
@@ -147,7 +148,7 @@
-
-
- Ready to play? Before you do, you'll need to visit your
- profile to...
-
-
+
+
+ You haven't selected your sponsoring organization yet - you'll need to before you can play practice
+ challenges. Head over to your profile to select your sponsor, then return here to play!
+
+
+
+
+
Need a place to start?
+ Try some of these suggested searches:
+
+
+
+
Practice Area
[appQueryParamModel]="{ name: 'term', debounce: 500, resetQueryParams: ['skip', 'take'] }">
+ To play challenges on {{ appName }} you'll need to select your sponsoring organization. Their logo will
+ appear next to your name on scoreboards.
+
+
+ Some sponsors house other sponsors within them (e.g. the Department of Defense contains the Army).
+ If you're sponsored by one of these entities, you're free to name either the Department of the Defense
+ or your specific branch as your sponsor.
+
+
+
+ NOTE:
+ If your sponsor isn't represented here, please
+ file a support ticket.
+
+