diff --git a/Dockerfile b/Dockerfile index c4505ed3..85322458 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,6 @@ # multi-stage target: dev -FROM node:18-alpine as dev -ARG commit +FROM node:18-alpine AS dev WORKDIR /app COPY package.json package-lock.json tools/ ./ RUN npm install && \ @@ -9,13 +8,12 @@ RUN npm install && \ COPY . . RUN if [ -e "wmks.tar" ]; then tar xf wmks.tar -C node_modules/vmware-wmks; fi RUN $(npm root)/.bin/ng build gameboard-ui --output-path /app/dist && \ - $(npm root)/.bin/ng build gameboard-mks --base-href=/mks/ --output-path /app/dist/mks + $(npm root)/.bin/ng build gameboard-mks --base-href=/mks/ --output-path /app/dist/mks CMD ["npm", "start"] # multi-stage target: prod FROM nginx:alpine WORKDIR /var/www -ENV COMMIT=$commit COPY --from=dev /app/dist . COPY --from=dev /app/dist/assets/oidc-silent.html . COPY --from=dev /app/LICENSE.md ./LICENSE.md diff --git a/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.html b/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.html new file mode 100644 index 00000000..efee029a --- /dev/null +++ b/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.html @@ -0,0 +1,23 @@ + +

+ You've selected {{ teams.length }} teams for advancement. Choose a game + to which they'll advance, and specify whether you want their starting score to be migrated from the current + game. +

+ +
+ + +
+ +
+ +
+
diff --git a/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.scss b/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.ts b/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.ts new file mode 100644 index 00000000..eaf48e89 --- /dev/null +++ b/projects/gameboard-ui/src/app/admin/components/advance-teams-modal/advance-teams-modal.component.ts @@ -0,0 +1,48 @@ +import { Component, inject, OnInit } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { CoreModule } from "../../../core/core.module"; +import { SimpleEntity } from '@/api/models'; +import { Game } from '@/api/game-models'; +import { GameService } from '@/api/game.service'; +import { firstValueFrom } from 'rxjs'; +import { TeamService } from '@/api/team.service'; + +@Component({ + selector: 'app-advance-teams-modal', + standalone: true, + imports: [CommonModule, CoreModule], + templateUrl: './advance-teams-modal.component.html', + styleUrls: ['./advance-teams-modal.component.scss'] +}) +export class AdvanceTeamsModalComponent implements OnInit { + private gameService = inject(GameService); + private teamService = inject(TeamService); + + game?: SimpleEntity; + onConfirm?: (targetGame: SimpleEntity) => Promise + teams: SimpleEntity[] = []; + + protected includeScores = false; + protected selectedGame?: Game; + protected targetGames: Game[] = []; + + async ngOnInit(): Promise { + this.targetGames = await firstValueFrom(this.gameService.list({ filter: ['advanceable'] })); + } + + protected async handleConfirm() { + if (!this.selectedGame) { + return; + } + + await this.teamService.advance({ + gameId: this.selectedGame.id, + includeScores: this.includeScores, + teamIds: this.teams.map(t => t.id) + }); + + if (this.onConfirm) { + await this.onConfirm(this.selectedGame); + } + } +} diff --git a/projects/gameboard-ui/src/app/admin/components/game-center/game-center-team-detail/game-center-team-detail.component.html b/projects/gameboard-ui/src/app/admin/components/game-center/game-center-team-detail/game-center-team-detail.component.html index f5abcbf4..c074de95 100644 --- a/projects/gameboard-ui/src/app/admin/components/game-center/game-center-team-detail/game-center-team-detail.component.html +++ b/projects/gameboard-ui/src/app/admin/components/game-center/game-center-team-detail/game-center-team-detail.component.html @@ -1,14 +1,14 @@

Advancement

-
-
-
Advanced from
+
+
+
Advanced from
{{team.advancement.fromGame.name}}
-
-
Score
+
+
Score
{{team.advancement.score || 0}}
diff --git a/projects/gameboard-ui/src/app/admin/components/game-center/game-center-teams/game-center-teams.component.html b/projects/gameboard-ui/src/app/admin/components/game-center/game-center-teams/game-center-teams.component.html index 017f912c..29593529 100644 --- a/projects/gameboard-ui/src/app/admin/components/game-center/game-center-teams/game-center-teams.component.html +++ b/projects/gameboard-ui/src/app/admin/components/game-center/game-center-teams/game-center-teams.component.html @@ -26,6 +26,12 @@ {{ game.isTeamGame ? "Team" : "Player" }}{{ selectedTeamIds.length === 1 ? "" : "s" }} + +
@@ -148,7 +148,7 @@

Team Up

placeholder="Enter your invitation code here to join a team">
@@ -165,7 +165,7 @@

Team Up

- + Unenroll
diff --git a/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.ts b/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.ts index 98aafdac..3662c7fb 100644 --- a/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.ts +++ b/projects/gameboard-ui/src/app/game/player-enroll/player-enroll.component.ts @@ -2,8 +2,7 @@ // Released under a MIT (SEI)-style license. See LICENSE.md in the project root for license information. import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; -import { faCopy, faEdit, faPaste, faTrash, faUser } from '@fortawesome/free-solid-svg-icons'; -import { firstValueFrom, Observable, of, Subject, Subscription, timer } from 'rxjs'; +import { BehaviorSubject, firstValueFrom, Observable, of, Subscription, timer } from 'rxjs'; import { map, tap, delay, first } from 'rxjs/operators'; import { GameContext } from '../../api/models'; import { HubPlayer, NewPlayer, Player, PlayerEnlistment, PlayerRole, TimeWindow } from '../../api/player-models'; @@ -45,18 +44,13 @@ export class PlayerEnrollComponent implements OnInit, OnDestroy { protected hasSelectedSponsor = false; protected managerRole = PlayerRole.manager; protected isEnrolled$: Observable; - protected isManager$ = new Subject(); + protected isManager$ = new BehaviorSubject(null); protected isRegistrationOpen = false; protected hasTeammates$: Observable = of(false); protected unenrollTooltip?: string; private hubSub?: Subscription; fa = fa; - faUser = faUser; - faEdit = faEdit; - faCopy = faCopy; - faPaste = faPaste; - faTrash = faTrash; constructor( private api: PlayerService, @@ -75,6 +69,10 @@ export class PlayerEnrollComponent implements OnInit, OnDestroy { ctx.game.registration = new TimeWindow(ctx.game?.registrationOpen, ctx.game?.registrationClose); this.isRegistrationOpen = ctx.game.registrationType !== GameRegistrationType.none; this.enrollTooltip = this.isRegistrationOpen ? "" : "Registration is currently closed for this game."; + + if (this.isManager$.value === null) { + this.isManager$.next(ctx.player?.isManager || true); + } }), tap((gc) => { if (gc.player.nameStatus && gc.player.nameStatus != 'pending') { @@ -112,13 +110,13 @@ export class PlayerEnrollComponent implements OnInit, OnDestroy { ngOnInit(): void { this.manageUnenrollAvailability(this.hubService.actors$.getValue()); - this.isManager$.next(this.ctx.player.isManager); this.hubSub = this.hubService.actors$.subscribe(a => { this.manageUnenrollAvailability(a); const manager = a.find(a => a.isManager); - if (manager) - this.isManager$.next(manager?.id == this.ctx.player.id); + if (this.ctx.player?.id && manager) { + this.isManager$.next(manager.id == this.ctx.player.id); + } }); } diff --git a/projects/gameboard-ui/src/app/services/font-awesome.service.ts b/projects/gameboard-ui/src/app/services/font-awesome.service.ts index 51fc3c93..36e34960 100644 --- a/projects/gameboard-ui/src/app/services/font-awesome.service.ts +++ b/projects/gameboard-ui/src/app/services/font-awesome.service.ts @@ -18,6 +18,7 @@ import { faChessBoard, faChevronDown, faChevronUp, + faCircleArrowUp, faCircleUser, faClipboard, faClock, @@ -47,6 +48,7 @@ import { faLongArrowAltDown, faMapMarker, faPaperclip, + faPaste, faPeopleGroup, faPerson, faPlus, @@ -92,6 +94,7 @@ export const fa = { chessBoard: faChessBoard, chevronDown: faChevronDown, chevronUp: faChevronUp, + circleArrowUp: faCircleArrowUp, circleUser: faCircleUser, clipboard: faClipboard, clock: faClock, @@ -121,6 +124,7 @@ export const fa = { mapMarker: faMapMarker, openId: faOpenid, paperclip: faPaperclip, + paste: faPaste, peopleGroup: faPeopleGroup, person: faPerson, plus: faPlus,