Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.14.0 #154

Merged
merged 28 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7c4a249
Resolved an issue that caused the user name input box to behave errat…
sei-bstein Dec 6, 2023
5845873
Resolved an issue that could cause the component which presents chall…
sei-bstein Dec 6, 2023
7940234
Remove unused refs
sei-bstein Dec 6, 2023
fe51e81
Initial draft of 135/165
sei-bstein Dec 7, 2023
1f6232d
Finished draft of 135/165.
sei-bstein Dec 11, 2023
7f8fb4c
Don't show duplicate answers in historical attempts.
sei-bstein Dec 11, 2023
8bc74bf
Working on players report
sei-bstein Dec 14, 2023
dfeb2fb
Merge branch 'main' into next
sei-bstein Dec 14, 2023
2f1df39
Merge branch 'next' into issue/309
sei-bstein Dec 14, 2023
cf22dc7
Finish mvp of Players Report.
sei-bstein Dec 14, 2023
1513083
Add summary card to players report. Resolves GBAPI#309 pending feedback.
sei-bstein Dec 14, 2023
5274f77
Initial draft of Challenges Report. Still needs summary card.
sei-bstein Dec 15, 2023
661449f
Mvp of #310.
sei-bstein Dec 18, 2023
14b915f
First draft of responsive nav. Need to adjust to avoid menu markup du…
sei-bstein Dec 18, 2023
5ca58ba
Merge branch 'hotfix/responsive-navbar' into next
sei-bstein Dec 18, 2023
b34d4ac
Merge branch 'hotfix/responsive-navbar' into issue/310
sei-bstein Dec 18, 2023
1448657
Removed unnecessary generic type on ReportComponentBase
sei-bstein Dec 18, 2023
bbc7373
More fiddling with responsive menu and other not-as-responsive things.
sei-bstein Dec 18, 2023
5b055fd
Refining modals for players report.
sei-bstein Dec 19, 2023
82bc09c
Merge branch 'hotfix/responsive-navbar' into next
sei-bstein Dec 19, 2023
6235b9d
Merge branch 'next' into issue/310
sei-bstein Dec 19, 2023
5dc8d2a
Finish players report modal for participation.
sei-bstein Dec 19, 2023
28bffb7
Fixed a few paging bugs in reporting.
sei-bstein Dec 19, 2023
34376ed
Make unsubscriber service transient so that it correctly disposes subs.
sei-bstein Dec 19, 2023
1c6479c
Correct missing provider for profile-editor
sei-bstein Dec 19, 2023
e549968
Fix reports module dependency and some spoonsor select bugs.
sei-bstein Dec 19, 2023
e81b785
Shorten autosave delay to 1.5 sec on challenge responses.
sei-bstein Dec 19, 2023
8ed254c
Correct comment
sei-bstein Dec 19, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 }}
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