Skip to content

Commit

Permalink
v3.14.0 (#154)
Browse files Browse the repository at this point in the history
* Resolved an issue that caused the user name input box to behave erratically for fast typers. Also applied better styling to pending user/player name change requests.

* Resolved an issue that could cause the component which presents challenge questions to spam the API if a 500 is returned.

* Remove unused refs

* Initial draft of 135/165

* Finished draft of 135/165.

* Don't show duplicate answers in historical attempts.

* Working on players report

* Finish mvp of Players Report.

* Add summary card to players report. Resolves GBAPI#309 pending feedback.

* Initial draft of Challenges Report. Still needs summary card.

* Mvp of #310.

* First draft of responsive nav. Need to adjust to avoid menu markup duplication.

* Removed unnecessary generic type on ReportComponentBase

* More fiddling with responsive menu and other not-as-responsive things.

* Refining modals for players report.

* Finish players report modal for participation.

* Fixed a few paging bugs in reporting.

* Make unsubscriber service transient so that it correctly disposes subs.

* Correct missing provider for profile-editor

* Fix reports module dependency and some spoonsor select bugs.

* Shorten autosave delay to 1.5 sec on challenge responses.

* Correct comment
  • Loading branch information
sei-bstein authored Dec 19, 2023
1 parent 89d8a5c commit 2cb874a
Show file tree
Hide file tree
Showing 83 changed files with 1,367 additions and 321 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { Subject, debounceTime, filter, switchMap, tap } from 'rxjs';
@Component({
selector: 'app-challenge-spec-editor',
templateUrl: './challenge-spec-editor.component.html',
styleUrls: ['./challenge-spec-editor.component.scss']
styleUrls: ['./challenge-spec-editor.component.scss'],
providers: [UnsubscriberService]
})
export class ChallengeSpecEditorComponent implements OnChanges {
@Input() spec?: Spec;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export interface ExternalGameAdminContext {
@Component({
selector: 'app-external-game-admin',
templateUrl: './external-game-admin.component.html',
styleUrls: ['./external-game-admin.component.scss']
styleUrls: ['./external-game-admin.component.scss'],
providers: [UnsubscriberService]
})
export class ExternalGameAdminComponent implements OnInit {
private autoUpdateInterval = 30000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ interface PracticeSettingsContext {
@Component({
selector: 'app-practice-settings',
templateUrl: './practice-settings.component.html',
styleUrls: ['./practice-settings.component.scss']
styleUrls: ['./practice-settings.component.scss'],
providers: [UnsubscriberService]
})
export class PracticeSettingsComponent implements OnInit {
ctx: PracticeSettingsContext | null = null;
Expand Down
1 change: 1 addition & 0 deletions projects/gameboard-ui/src/app/api/board-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PlayerMode, PlayerRole, TimeWindow } from "./player-models";
export interface Challenge {
id: string;
specId: string;
teamId: string;
name: string;
tag: string;
startTime: Date;
Expand Down
29 changes: 27 additions & 2 deletions projects/gameboard-ui/src/app/api/board.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { GameSessionService } from '../services/game-session.service';
import { ConfigService } from '../utility/config.service';
import { BoardPlayer, BoardSpec, Challenge, ChallengeSummary, ChangedChallenge, ConsoleActor, NewChallenge, ObserveChallenge, SectionSubmission, VmConsole } from './board-models';
import { BoardPlayer, BoardSpec, Challenge, ChallengeResult, ChallengeSummary, ChangedChallenge, ConsoleActor, NewChallenge, ObserveChallenge, VmConsole } from './board-models';
import { NowService } from '@/services/now.service';

@Injectable({ providedIn: 'root' })
export class BoardService {
Expand All @@ -16,7 +17,8 @@ export class BoardService {
constructor(
private http: HttpClient,
private config: ConfigService,
private gameSessionService: GameSessionService
private gameSessionService: GameSessionService,
private nowService: NowService
) {
this.url = config.apphost + 'api';
}
Expand Down Expand Up @@ -98,6 +100,29 @@ export class BoardService {
return b;
}

getChallengeColor(challengeInfo: { id: string, endTime?: Date, isDisabled: boolean, isLocked: boolean, result: ChallengeResult }) {
if (!challengeInfo.endTime) {
return "white";
}

if (challengeInfo.isDisabled || challengeInfo.isLocked) {
return "black";
}

if (challengeInfo.result == "success") {
return "lime";
}

if (challengeInfo.result == "partial") {
return "yellow";
}

if (challengeInfo.endTime < this.nowService.now())
return "red";

return "blue";
}

setColor(s: BoardSpec): void {
s.c = !!s.instance?.state.id
? s.instance.state.endTime.match(/^0001/) ? 'white' : 'black'
Expand Down
18 changes: 18 additions & 0 deletions projects/gameboard-ui/src/app/api/challenges.models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@ export interface LocalActiveChallenge extends ActiveChallenge {
session: LocalTimeWindow;
}

export interface ChallengeSubmissionAnswers {
questionSetIndex: number;
answers: string[];
}

export interface ChallengeSubmissionViewModel {
sectionIndex: number;
answers: string[];
submittedOn: Date;
}

export interface GetChallengeSubmissionsResponse {
challengeId: string;
teamId: string;
pendingAnswers: ChallengeSubmissionAnswers | null;
submittedAnswers: ChallengeSubmissionViewModel[];
}

export interface UserApiActiveChallenges {
user: SimpleEntity;
competition: ApiActiveChallenge[];
Expand Down
10 changes: 9 additions & 1 deletion projects/gameboard-ui/src/app/api/challenges.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Observable, Subject, map, switchMap, tap } from 'rxjs';
import { Challenge, NewChallenge, SectionSubmission } from './board-models';
import { ApiUrlService } from '@/services/api-url.service';
import { activeChallengesStore } from '@/stores/active-challenges.store';
import { ChallengeSolutionGuide, LocalActiveChallenge, UserActiveChallenges, UserApiActiveChallenges } from './challenges.models';
import { ChallengeSolutionGuide, ChallengeSubmissionAnswers, GetChallengeSubmissionsResponse, LocalActiveChallenge, UserActiveChallenges, UserApiActiveChallenges } from './challenges.models';
import { LocalTimeWindow } from '@/core/models/api-time-window';
import { PlayerMode } from './player-models';

Expand Down Expand Up @@ -88,4 +88,12 @@ export class ChallengesService {
public getSolutionGuide(challengeId: string): Observable<ChallengeSolutionGuide | null> {
return this.http.get<ChallengeSolutionGuide>(this.apiUrl.build(`challenge/${challengeId}/solution-guide`));
}

public getSubmissions(challengeId: string): Observable<GetChallengeSubmissionsResponse> {
return this.http.get<GetChallengeSubmissionsResponse>(this.apiUrl.build(`challenge/${challengeId}/submissions`));
}

public savePendingSubmission(challengeId: string, submission: ChallengeSubmissionAnswers) {
return this.http.put(this.apiUrl.build(`challenge/${challengeId}/submissions/pending`), submission);
}
}
2 changes: 1 addition & 1 deletion projects/gameboard-ui/src/app/api/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { map } from 'rxjs/operators';
import { ConfigService } from '../utility/config.service';
import { Announcement, ApiUser, ChangedUser, NewUser, TreeNode, TryCreateUserResult } from './user-models';
import { LogService } from '@/services/log.service';
Expand Down
1 change: 1 addition & 0 deletions projects/gameboard-ui/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<app-sponsor-select-banner></app-sponsor-select-banner>
<app-nav></app-nav>
</div>
<app-gameboard-signalr-hubs></app-gameboard-signalr-hubs>
<app-system-notifications></app-system-notifications>
<app-message-board></app-message-board>
<router-outlet></router-outlet>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { combineLatest, map } from 'rxjs';
@Component({
selector: 'app-gameboard-signalr-hubs',
templateUrl: './gameboard-signalr-hubs.component.html',
styleUrls: ['./gameboard-signalr-hubs.component.scss']
styleUrls: ['./gameboard-signalr-hubs.component.scss'],
providers: [UnsubscriberService]
})
export class GameboardSignalRHubsComponent implements OnDestroy {
protected isDevMode = false;
Expand Down
54 changes: 52 additions & 2 deletions projects/gameboard-ui/src/app/components/nav/nav.component.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<nav [class]="customBackground">
<nav [class]="customBackground" class="nav-lg">
<div class="nav-items d-flex align-items-center justify-content-end">
<app-gameboard-signalr-hubs></app-gameboard-signalr-hubs>
<div class="flex-grow-1"></div>
<a class="btn btn-link text-success mx-1" routerLinkActive="text-info" [routerLink]="['/home']">Home</a>
<ng-container *ngIf="(toc$ | async)?.length">
Expand Down Expand Up @@ -32,6 +31,57 @@
</div>
</nav>

<nav class="nav-sm bg-dark">
<div class="flex-grow-1"></div>
<div class="btn-group" dropdown placement="bottom right">
<button id="nav-toggle" dropdownToggle type="button" class="btn btn-info dropdown-toggle d-block"
aria-controls="dropdown-animated">
<fa-icon [icon]="fa.bars"></fa-icon>
Menu
</button>

<ul class="dropdown-menu dropdown-menu-right" *dropdownMenu>
<li>
<a routerLinkActive="active" [routerLink]="['/home']">Home</a>
</li>
<ng-container *ngIf="(toc$ | async)?.length">
<li *ngFor="let t of toc$ | async">
<a [routerLink]="['doc', t.link]" routerLinkActive="active">{{t.display}}</a>
</li>
</ng-container>
<li *ngIf="isPracticeModeEnabled">
<a routerLinkActive="active" [routerLink]="['practice']">Practice</a>
</li>
<ng-container *ngIf="user$ | async as user; else unauthed">
<li>
<a routerLinkActive="active" [routerLink]="['support']">
<span>Support</span>
<app-support-pill></app-support-pill>
</a>
</li>
<li>
<a routerLinkActive="active" [routerLink]="profileUrl">Profile</a>
</li>
<li *ngIf="canAccessReporting$ | async">
<a routerLinkActive="active" [routerLink]="['/reports']">
Reports
</a>
<span class="badge badge-info">[BETA]</span>
</li>
<li *ngIf="user.isAdmin || user.isDirector || user.isRegistrar ||
user.isDesigner || user.isObserver || user.isSupport">
<a routerLinkActive="active" [routerLink]="['/admin']">
Admin
</a>
</li>
<li *ngIf="user?.id">
<a (click)="logout()">Log out</a>
</li>
</ng-container>
</ul>
</div>
</nav>

<ng-template #unauthed>
<a class="btn btn-link text-success mx-1" routerLinkActive="text-info" [routerLink]="profileUrl">Log in</a>
</ng-template>
52 changes: 43 additions & 9 deletions projects/gameboard-ui/src/app/components/nav/nav.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,53 @@
}
}

nav a {
font-size: 1.5rem;
@media (max-width: 800px) {
.nav-sm {
display: flex;

.badge {
display: inline-block;
font-size: 0.5rem !important;
// margin-right: 12px;
}

li {
padding-left: 4px;
}
}

.nav-lg {
display: none;
}
}

.nav-items {
a {
@media(min-width: 801px) {
.nav-sm {
display: none !important;
}

.nav-lg {
display: block;

.nav-items {
a {
display: block;
font-size: 1.5rem;
}
}

.badge {
display: inline-block;
font-size: 0.75rem;
margin-left: -4px;
margin-right: 12px;
}
}
}

.badge {
display: inline-block;
font-size: 0.75rem;
margin-left: -4px;
margin-right: 12px;

.nav-sm {
display: flex;
align-items: center;
justify-content: flex-end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { Title } from '@angular/platform-browser';
import { Observable, map } from 'rxjs';
import { ReportsService } from '@/reports/reports.service';
import { RouterService } from '@/services/router.service';
import { fa } from '@/services/font-awesome.service';

@Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.scss']
styleUrls: ['./nav.component.scss'],
providers: [UnsubscriberService]
})
export class AppNavComponent implements OnInit {
user$!: Observable<ApiUser | null>;
Expand All @@ -23,6 +25,8 @@ export class AppNavComponent implements OnInit {
customBackground = "";
env: any;

protected fa = fa;
protected isCollapsed = false;
protected isPracticeModeEnabled = false;
protected profileUrl?: string;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ timeRemaining$ | async | countdown }}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { NowService } from '@/services/now.service';
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { Observable, map, of, tap, timer } from 'rxjs';

@Component({
selector: 'app-countdown',
templateUrl: './countdown.component.html',
styleUrls: ['./countdown.component.scss']
})
export class CountdownComponent implements OnChanges {
// note that this should be in MS since epoch (e.g. new Date().valueOf())
@Input() countdownTo?: number;

protected timeRemaining$: Observable<number> = of(0);

constructor(private nowService: NowService) { }

ngOnChanges(changes: SimpleChanges): void {
if (this.countdownTo) {
this.timeRemaining$ = timer(0, 1000).pipe(
map(() => {
if (!this.countdownTo)
return 0;

return this.countdownTo - this.nowService.now().valueOf();
})
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ export class SelectPagerComponent implements OnChanges {
protected pageNumber = 0;
protected pages: number[] = [];

constructor(private route: ActivatedRoute) { }

ngOnChanges(changes: SimpleChanges): void {
const shouldCalcPages = (changes.itemCount || changes.pageSize);
const itemCount = changes.itemCount?.currentValue || this.itemCount;
Expand Down Expand Up @@ -50,7 +48,9 @@ export class SelectPagerComponent implements OnChanges {
clampedPageNumber = Math.min(pageNumber, this.pages.length - 1);
clampedPageNumber = clampedPageNumber < 0 ? 0 : clampedPageNumber;

this.pageNumber = clampedPageNumber;
this.change.emit({ pageNumber: this.pageNumber, pageSize: this.pageSize! });
if (this.pageNumber !== clampedPageNumber) {
this.pageNumber = clampedPageNumber;
this.change.emit({ pageNumber: this.pageNumber, pageSize: this.pageSize! });
}
}
}
Loading

0 comments on commit 2cb874a

Please sign in to comment.