Skip to content

Commit

Permalink
v3.25.1 (#209)
Browse files Browse the repository at this point in the history
* Misc cleanup, fix enrollment trend, fix game level feedback alignment

* Improve visibility of incorrect questions. Explain no performance if none is available in the challenges report.

* Fix a reloading bug on competitive play page

* Make support notifications closeable and open in new tab

* Style toastify close button a bit
  • Loading branch information
sei-bstein authored Dec 4, 2024
1 parent e700334 commit be822f0
Show file tree
Hide file tree
Showing 20 changed files with 177 additions and 174 deletions.
4 changes: 1 addition & 3 deletions projects/gameboard-ui/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ import { UserNavItemComponent } from './standalone/user/components/user-nav-item
})
export class AppModule { }

export function loadSettings(
config: ConfigService,
): (() => Observable<any>) {
export function loadSettings(config: ConfigService): (() => Observable<any>) {
return (): Observable<any> => config.load();
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div class="cumulative-time-clock-component">
<span *ngIf="session else noSession" [class]="(time$ | async) || 0 | countdowncolor">
<span *ngIf="session else noSession">
{{ ((time$ | async) || 0 | clock) || "--" }}
</span>
<ng-template #noSession>--</ng-template>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LogService } from '@/services/log.service';
import { AfterViewInit, Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
import { LogService } from '@/services/log.service';
import { Chart, ChartConfiguration, ChartConfigurationCustomTypesPerDataset } from 'chart.js';

export type LineChartConfig = ChartConfiguration<"line", number[], string> | ChartConfigurationCustomTypesPerDataset<"line", number[], string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

<ng-container *ngIf="spec.instance?.state as state">
<ng-container *ngIf="!!state.challenge && pendingAnswers">

<markdown [data]="state.challenge.sectionText"></markdown>

<div *ngFor="let q of state.challenge.questions; let i = index" class="form-group p-4 mt-4"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ label {

.incorrect {
background-color: lighten($warning, 5%);
color: $body-bg;
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ <h2>Info</h2>
</div>
</div>

<div class="row align-items-center justify-content-center">
<div class="col-12 page-width scoreboard">
<div class="row justify-content-center">
<div class="col-6 scoreboard">
<h2 id="scoreboard" class="text-center my-4">
<span>Scoreboard</span>&nbsp;&nbsp;
<a [routerLink]="['/game', ctx.game.id, 'scoreboard']">
Expand All @@ -95,8 +95,7 @@ <h2 id="scoreboard" class="text-center my-4">
</h2>
<app-scoreboard [gameId]="ctx.game.id"></app-scoreboard>
</div>
<div class="col-xl-5 pr-5 my-4"
*ngIf="ctx.game.feedbackTemplate?.game?.length && (!ctx.player.session?.isBefore)">
<div class="col-6 pr-5 my-4" *ngIf="ctx.game.feedbackTemplate?.game?.length && (!ctx.player.session?.isBefore)">
<app-feedback-form *ngIf="ctx.player.session" [title]="ctx.game.name + ' Feedback'" [type]="'game'"
[boardPlayer]="boardPlayer">
</app-feedback-form>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,133 +18,132 @@
<div class="container-fluid">
<app-error-div [errors]="errors"></app-error-div>

<div>
<div class="col m-2 p-4">
<h3 class="font-weight-bold text-muted">To start a challenge, click a circle on the below gameboard:</h3>
</div>
<div class="row justify-content-center">
<div class="mapbox col m-4 p-4">
<div #callout class="callout bg-primary m-0 p-4" [hidden]="!this.hoveredItem">
<span>{{this.hoveredItem?.lockedText || this.hoveredItem?.name}}</span><br />
<span>Points: {{this.hoveredItem?.points}}</span>
</div>
<svg viewBox="0 0 100 100">
<svg:image [attr.href]="ctx?.game?.mapUrl" width="100" height="100" />
<ng-container *ngFor="let c of ctx?.game?.specs">
<a class="mapbox-dot cursor-pointer" (mouseenter)="mouseenter($event, c)"
(mouseleave)="mouseleave($event, c)">
<svg:circle [attr.cx]="c.x*100" [attr.cy]="c.y*100" [attr.r]="c.r*100" [attr.fill]="c.c"
(click)="select(c)" [attr.fill]="c.c"></svg:circle>
</a>
</ng-container>
</svg>
<div class="row justify-content-center">
<div class="mapbox col m-4 p-4">
<h3 class="text-center font-weight-bold text-muted mb-2">
Select a circle on the gameboard below to start playing:
</h3>

<div #callout class="callout bg-primary m-0 p-4" [hidden]="!this.hoveredItem">
<span>{{this.hoveredItem?.lockedText || this.hoveredItem?.name}}</span><br />
<span>Points: {{this.hoveredItem?.points}}</span>
</div>
<svg viewBox="0 0 100 100">
<svg:image [attr.href]="ctx?.game?.mapUrl" width="100" height="100" />
<ng-container *ngFor="let c of ctx?.game?.specs">
<a class="mapbox-dot cursor-pointer" (mouseenter)="mouseenter($event, c)"
(mouseleave)="mouseleave($event, c)">
<svg:circle [attr.cx]="c.x*100" [attr.cy]="c.y*100" [attr.r]="c.r*100" [attr.fill]="c.c"
(click)="select(c)" [attr.fill]="c.c"></svg:circle>
</a>
</ng-container>
</svg>
</div>

<div class="quizbox col m-4 p-4">

<!-- not started, show preview -->
<ng-container *ngIf="selected as spec">
<div *ngIf="!spec.instance!.id" class="text-center mb-4">
<ng-container *ngIf="ctx.session.isDuring && !deploying">
<ng-container *ngIf="this.user$ | async as user">
<div *appIfHasPermission="'Play_ChooseChallengeVariant'" class="form-group">
<label for="variant-input">Variant</label>
<input type="number" class="form-control" [(ngModel)]="variant">
</div>
</ng-container>
<app-confirm-button btnClass="btn btn-success" (confirm)="launch(spec)" #startChallengeConfirmButton>
<span>Start Challenge</span>
</app-confirm-button>
<div *ngIf="!ctx.isPractice">
This will start the challenge timer. The time it takes to
earn points is a factor in tie-breaking.
<div class="quizbox col m-4 p-4">

<!-- not started, show preview -->
<ng-container *ngIf="selected as spec">
<div *ngIf="!spec.instance!.id" class="text-center mb-4">
<ng-container *ngIf="ctx.session.isDuring && !deploying">
<ng-container *ngIf="this.user$ | async as user">
<div *appIfHasPermission="'Play_ChooseChallengeVariant'" class="form-group">
<label for="variant-input">Variant</label>
<input type="number" class="form-control" [(ngModel)]="variant">
</div>
</ng-container>
<div *ngIf="deploying" class="text-center">
<app-spinner></app-spinner>
<ng-container *ngIf="etd$ | async as etd">
<div *ngIf="etd > 0">
<span class="text-muted">
Estimated time remaining:
</span>
<strong>{{etd}}</strong>s
</div>
</ng-container>
<app-confirm-button btnClass="btn btn-success" (confirm)="launch(spec)" #startChallengeConfirmButton>
<span>Start Challenge</span>
</app-confirm-button>
<div class="text-muted mt-2" *ngIf="!ctx.isPractice">
This will start the challenge timer. The time it takes to
earn points is a factor in tie-breaking.
</div>
</ng-container>
<div *ngIf="deploying" class="text-center">
<app-spinner></app-spinner>
<ng-container *ngIf="etd$ | async as etd">
<div *ngIf="etd > 0">
<span class="text-muted">
Estimated time remaining:
</span>
<strong>{{etd}}</strong>s
</div>
</ng-container>
</div>
</div>

<markdown [data]="spec.instance!.state.markdown || ''"></markdown>

<markdown *ngIf="spec.instance?.state?.challenge" [data]="spec.instance!.state.challenge.text || ''">
</markdown>

<app-challenge-solution-guide *ngIf="spec.instance?.id"
[challengeId]="spec.instance!.id"></app-challenge-solution-guide>

<ng-container *ngIf="!!spec.instance!.state && spec.instance!.state.isActive">
<h3>Gamespace Resources</h3>
<div *ngIf="!deploying && ctx.session.isDuring">
<div class="vms-container my-4">
<ul class="d-flex">
<li *ngFor="let vm of spec.instance!.state.vms">
<button class="btn btn-sm btn-dark mr-2" (click)="console(vm)">
<fa-icon [icon]="faTv"></fa-icon>
<span>{{vm.name}}</span>
</button>
</li>
</ul>
</div>
<markdown [data]="spec.instance!.state.markdown || ''"></markdown>

<div class="vm-controls-container my-4">
<app-confirm-button *ngIf="spec.instance!.state.vms?.length" btnClass="btn btn-sm btn-outline-warning"
(confirm)="stop(spec)">
<fa-icon [icon]="faTrash"></fa-icon>
<span>Destroy</span>
</app-confirm-button>
<app-confirm-button *ngIf="!spec.instance!.state.vms?.length"
btnClass="btn btn-sm btn-outline-warning" (confirm)="start(spec)">
<fa-icon [icon]="faBolt"></fa-icon>
<span>Deploy</span>
</app-confirm-button>
</div>
</div>
<div *ngIf="deploying" class="text-center">
<app-spinner></app-spinner>
</div>
</ng-container>
<markdown *ngIf="spec.instance?.state?.challenge" [data]="spec.instance!.state.challenge.text || ''">
</markdown>

<h3 *ngIf="spec.instance!.state.challenge?.questions?.length">Challenge Questions</h3>
<app-gamespace-quiz [challengeId]="spec.instance!.state.id" [spec]="spec!" [session]="ctx.session"
(graded)="graded()"></app-gamespace-quiz>

<div *ngIf="spec.instance?.id" class="d-flex align-items-baseline my-5">
<div class="flex-grow-1">
Support Code:
<span class="text-success m-2 p-2 cursor-pointer" tooltip="Click to copy your challenge support code"
appCopyOnClick>
{{ spec.instance?.id | slice:0:8 }} {{ spec.tag }}
</span>
<app-challenge-solution-guide *ngIf="spec.instance?.id"
[challengeId]="spec.instance!.id"></app-challenge-solution-guide>

<ng-container *ngIf="!!spec.instance!.state && spec.instance!.state.isActive">
<h3>Gamespace Resources</h3>
<div *ngIf="!deploying && ctx.session.isDuring">
<div class="vms-container my-4">
<ul class="d-flex">
<li *ngFor="let vm of spec.instance!.state.vms">
<button class="btn btn-sm btn-dark mr-2" (click)="console(vm)">
<fa-icon [icon]="faTv"></fa-icon>
<span>{{vm.name}}</span>
</button>
</li>
</ul>
</div>

<div>
<span class="mr-2">
Need Challenge Support?
</span>
<span class="my-2 py-2">
<a class="btn btn-success" target="_blank" [routerLink]="['/support/create']"
[queryParams]="{cid: spec.instance?.id!}">
<span>Create Ticket</span>
</a>
</span>
<div class="vm-controls-container my-4">
<app-confirm-button *ngIf="spec.instance!.state.vms?.length" btnClass="btn btn-sm btn-outline-warning"
(confirm)="stop(spec)">
<fa-icon [icon]="faTrash"></fa-icon>
<span>Destroy</span>
</app-confirm-button>
<app-confirm-button *ngIf="!spec.instance!.state.vms?.length" btnClass="btn btn-sm btn-outline-warning"
(confirm)="start(spec)">
<fa-icon [icon]="faBolt"></fa-icon>
<span>Deploy</span>
</app-confirm-button>
</div>
</div>

<div *ngIf="spec.instance!.state.challenge && ctx.game.feedbackTemplate?.challenge?.length">
<app-feedback-form [boardPlayer]="ctx" title="Challenge Feedback" [spec]="spec"
[type]="'challenge'"></app-feedback-form>
<div *ngIf="deploying" class="text-center">
<app-spinner></app-spinner>
</div>
</ng-container>
</div>

<h3 *ngIf="spec.instance!.state.challenge?.questions?.length">Challenge Questions</h3>
<app-gamespace-quiz [challengeId]="spec.instance!.state.id" [spec]="spec!" [session]="ctx.session"
(graded)="graded()"></app-gamespace-quiz>

<div *ngIf="spec.instance?.id" class="d-flex align-items-baseline my-5">
<div class="flex-grow-1">
Support Code:
<span class="text-success m-2 p-2 cursor-pointer" tooltip="Click to copy your challenge support code"
appCopyOnClick>
{{ spec.instance?.id | slice:0:8 }} {{ spec.tag }}
</span>
</div>

<div>
<span class="mr-2">
Need Challenge Support?
</span>
<span class="my-2 py-2">
<a class="btn btn-success" target="_blank" [routerLink]="['/support/create']"
[queryParams]="{cid: spec.instance?.id!}">
<span>Create Ticket</span>
</a>
</span>
</div>
</div>

<div *ngIf="spec.instance!.state.challenge && ctx.game.feedbackTemplate?.challenge?.length">
<app-feedback-form [boardPlayer]="ctx" title="Challenge Feedback" [spec]="spec"
[type]="'challenge'"></app-feedback-form>
</div>
</ng-container>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,3 @@
max-width: 300px;
max-height: 300px;
}

.countdown-green {
color: $success;
}

.countdown-yellow {
color: $warning;
}

.countdown-red {
color: $danger;
}

// Uses a 16 : 10 ratio, but can be changed here
iframe {
// aspect-ratio: 16 / 10;
margin: auto;
display: block;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ActivatedRoute } from '@angular/router';
import { firstValueFrom, merge, Observable, of, Subject, timer } from 'rxjs';
import { catchError, debounceTime, filter, map, switchMap, tap } from 'rxjs/operators';
import { faArrowLeft, faBolt, faExclamationTriangle, faTrash, faTv } from '@fortawesome/free-solid-svg-icons';

import { BoardPlayer, BoardSpec, Challenge, NewChallenge, VmState } from '@/api/board-models';
import { BoardService } from '@/api/board.service';
import { ApiUser } from '@/api/user-models';
Expand Down Expand Up @@ -52,12 +51,12 @@ export class GameboardPageComponent {

constructor(
challengeService: ChallengesService,
route: ActivatedRoute,
title: Title,
usersvc: UserService,
private api: BoardService,
private config: ConfigService,
private hub: NotificationService,
protected route: ActivatedRoute,
private routerService: RouterService,
private unsub: UnsubscriberService,
private windowService: WindowService
Expand Down
Loading

0 comments on commit be822f0

Please sign in to comment.