diff --git a/package-lock.json b/package-lock.json
index d83076d1..35be8f39 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -41,7 +41,7 @@
"ng2-charts": "^4.1.1",
"ngx-bootstrap": "^10.3.0",
"ngx-markdown": "^15.1.2",
- "oidc-client-ts": "^2.2.2",
+ "oidc-client-ts": "^3.1.0",
"rxjs": "^7.8.0",
"toastify-js": "^1.12.0",
"tslib": "^2.1.0",
@@ -5044,10 +5044,6 @@
"node": ">= 8"
}
},
- "node_modules/crypto-js": {
- "version": "4.2.0",
- "license": "MIT"
- },
"node_modules/css-loader": {
"version": "6.7.3",
"dev": true,
@@ -7815,7 +7811,9 @@
}
},
"node_modules/http-proxy-middleware": {
- "version": "2.0.6",
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz",
+ "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -8752,8 +8750,13 @@
"license": "MIT"
},
"node_modules/jwt-decode": {
- "version": "3.1.2",
- "license": "MIT"
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz",
+ "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
},
"node_modules/karma": {
"version": "6.4.1",
@@ -10405,14 +10408,15 @@
"license": "MIT"
},
"node_modules/oidc-client-ts": {
- "version": "2.2.2",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/oidc-client-ts/-/oidc-client-ts-3.1.0.tgz",
+ "integrity": "sha512-IDopEXjiwjkmJLYZo6BTlvwOtnlSniWZkKZoXforC/oLZHC9wkIxd25Kwtmo5yKFMMVcsp3JY6bhcNJqdYk8+g==",
"license": "Apache-2.0",
"dependencies": {
- "crypto-js": "^4.1.1",
- "jwt-decode": "^3.1.2"
+ "jwt-decode": "^4.0.0"
},
"engines": {
- "node": ">=12.13.0"
+ "node": ">=18"
}
},
"node_modules/on-finished": {
diff --git a/package.json b/package.json
index 685c09c4..b947a0a9 100644
--- a/package.json
+++ b/package.json
@@ -45,7 +45,7 @@
"ng2-charts": "^4.1.1",
"ngx-bootstrap": "^10.3.0",
"ngx-markdown": "^15.1.2",
- "oidc-client-ts": "^2.2.2",
+ "oidc-client-ts": "^3.1.0",
"rxjs": "^7.8.0",
"toastify-js": "^1.12.0",
"tslib": "^2.1.0",
diff --git a/projects/gameboard-mks/src/styles.scss b/projects/gameboard-mks/src/styles.scss
index 83cdcb27..84d28abe 100644
--- a/projects/gameboard-mks/src/styles.scss
+++ b/projects/gameboard-mks/src/styles.scss
@@ -1,6 +1,6 @@
$primary: #181866;
$primary-hover: #131398;
-$danger: #A41E25;
+$danger: #a41e25;
$success: #41ad57;
$light: #f8f9fa;
$gray-200: #333;
@@ -11,7 +11,8 @@ $bg-tools: #444;
body {
background-color: $dark;
color: $light;
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
+ Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-size: 18px;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
@@ -75,9 +76,11 @@ button {
border: none;
cursor: default;
}
+
button:hover {
- background-color: $primary-hover
+ background-color: $primary-hover;
}
+
.btn-lg {
margin: 8px;
padding: 32px;
@@ -96,7 +99,8 @@ button:hover {
}
}
app-spinner {
- svg path, svg rect {
+ svg path,
+ svg rect {
fill: $primary;
}
}
@@ -109,12 +113,12 @@ app-spinner {
color: $light;
}
textarea {
- background-color: $gray-200;
- color: $gray-800;
+ background-color: $gray-200;
+ color: $gray-800;
}
textarea:focus {
- background-color: $gray-200;
- color: $gray-800;
+ background-color: $gray-200;
+ color: $gray-800;
}
input.form-check-input {
background-color: $gray-200;
diff --git a/projects/gameboard-ui/src/app/admin/challenge-browser/challenge-browser.component.html b/projects/gameboard-ui/src/app/admin/challenge-browser/challenge-browser.component.html
index 89efa34a..f1e93f7e 100644
--- a/projects/gameboard-ui/src/app/admin/challenge-browser/challenge-browser.component.html
+++ b/projects/gameboard-ui/src/app/admin/challenge-browser/challenge-browser.component.html
@@ -93,7 +93,7 @@
Challenge
+ class="btn btn-link text-success cursor-pointer py-0 px-0" (click)="auditFromGameEngine(selected.id)">
Audit from game engine?
diff --git a/projects/gameboard-ui/src/app/admin/components/active-challenges-modal/active-challenges-modal.component.html b/projects/gameboard-ui/src/app/admin/components/active-challenges-modal/active-challenges-modal.component.html
index 05fc143c..d8ac41e6 100644
--- a/projects/gameboard-ui/src/app/admin/components/active-challenges-modal/active-challenges-modal.component.html
+++ b/projects/gameboard-ui/src/app/admin/components/active-challenges-modal/active-challenges-modal.component.html
@@ -106,11 +106,11 @@
- There aren't any active challenges of this type right now.
+ There aren't any active challenges of this type right now.
- None of the active challenges match your search.
+ None of the active challenges match your search.
diff --git a/projects/gameboard-ui/src/app/admin/components/active-teams-modal/active-teams-modal.component.html b/projects/gameboard-ui/src/app/admin/components/active-teams-modal/active-teams-modal.component.html
index f0211a4e..b7448e46 100644
--- a/projects/gameboard-ui/src/app/admin/components/active-teams-modal/active-teams-modal.component.html
+++ b/projects/gameboard-ui/src/app/admin/components/active-teams-modal/active-teams-modal.component.html
@@ -104,11 +104,11 @@
- There aren't any active teams right now.
+ There aren't any active teams right now.
- There aren't any active teams which match your search.
+ There aren't any active teams which match your search.
diff --git a/projects/gameboard-ui/src/app/admin/components/admin-enroll-team-modal/admin-enroll-team-modal.component.html b/projects/gameboard-ui/src/app/admin/components/admin-enroll-team-modal/admin-enroll-team-modal.component.html
index dd6cccec..fcd47f0a 100644
--- a/projects/gameboard-ui/src/app/admin/components/admin-enroll-team-modal/admin-enroll-team-modal.component.html
+++ b/projects/gameboard-ui/src/app/admin/components/admin-enroll-team-modal/admin-enroll-team-modal.component.html
@@ -36,7 +36,7 @@
- Use the box above to search for the user(s) you want to enroll in this game.
+ Use the box above to search for the user(s) you want to enroll in this game.
@@ -46,7 +46,7 @@
size="tiny">
{{ user.name }}
-
{{ user.id | slice:0:8}}
+
{{ user.id | slice:0:8}}
diff --git a/projects/gameboard-ui/src/app/admin/dashboard/dashboard.component.html b/projects/gameboard-ui/src/app/admin/dashboard/dashboard.component.html
index d34b9a48..0cc4fc86 100644
--- a/projects/gameboard-ui/src/app/admin/dashboard/dashboard.component.html
+++ b/projects/gameboard-ui/src/app/admin/dashboard/dashboard.component.html
@@ -29,7 +29,7 @@
Cards
-
@@ -44,14 +44,14 @@
-
+
New Game
OR
-
+
Import From YAML
@@ -62,7 +62,7 @@
Upload or drop a YAML file
- (must be an array of games)
+ (must be an array of games)
diff --git a/projects/gameboard-ui/src/app/api/toc.service.ts b/projects/gameboard-ui/src/app/api/toc.service.ts
index 04aba6d3..50d44f6f 100644
--- a/projects/gameboard-ui/src/app/api/toc.service.ts
+++ b/projects/gameboard-ui/src/app/api/toc.service.ts
@@ -21,16 +21,16 @@ export class TocService {
private log: LogService
) {
const tag = `?t=${new Date().valueOf()}`;
- const tocUrl = `${config.tochost}/${config.settings.tocfile + ''}${tag}`;
+ const tocUrl = `${config.tochost}/${config.environment.settings.tocfile + ''}${tag}`;
let url = config.tochost;
// include toc folder
- const i = config.settings.tocfile?.lastIndexOf('/') || 0;
+ const i = config.environment.settings.tocfile?.lastIndexOf('/') || 0;
if (i > 0) {
- url += `/${config.settings.tocfile?.substring(0, i)}`;
+ url += `/${config.environment.settings.tocfile?.substring(0, i)}`;
}
- if (!!config.settings.tocfile) {
+ if (!!config.environment.settings.tocfile) {
this.toc$ = http.get(tocUrl).pipe(
catchError(err => {
// don't report error here - ops will know what the 404 means
diff --git a/projects/gameboard-ui/src/app/app.component.ts b/projects/gameboard-ui/src/app/app.component.ts
index d73f65bd..ff3d51c5 100644
--- a/projects/gameboard-ui/src/app/app.component.ts
+++ b/projects/gameboard-ui/src/app/app.component.ts
@@ -1,12 +1,13 @@
// 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, Inject, OnInit } from '@angular/core';
+import { DOCUMENT } from '@angular/common';
+import { Component, inject, Inject, OnInit } from '@angular/core';
+import { Title } from '@angular/platform-browser';
import { Observable } from 'rxjs';
import { LayoutService } from './utility/layout.service';
import { ConfigService } from './utility/config.service';
-import { DOCUMENT } from '@angular/common';
-import { Title } from '@angular/platform-browser';
+import { AuthService } from './utility/auth.service';
@Component({
selector: 'app-root',
@@ -14,22 +15,34 @@ import { Title } from '@angular/platform-browser';
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {
- protected customBackground = "";
+ private auth = inject(AuthService);
+ private config = inject(ConfigService);
+ private autoLogin: {
+ enabled: boolean;
+ tried: boolean;
+ };
+
+ protected customBackground = "custom-bg-black";
stickyMenu$: Observable;
constructor(
layoutService: LayoutService,
- private config: ConfigService,
private title: Title,
@Inject(DOCUMENT) private document: Document) {
+ this.autoLogin = { enabled: this.config.environment.settings.oidc.autoLogin, tried: false };
this.stickyMenu$ = layoutService.stickyMenu$;
}
- ngOnInit(): void {
- this.title.setTitle(this.config.settings.appname || 'Gameboard');
- if (this.config.settings.custom_background) {
- this.document.body.classList.add(this.config.settings.custom_background);
- this.customBackground = this.config.settings.custom_background || 'custom-bg-black';
+ async ngOnInit() {
+ this.title.setTitle(this.config.environment.settings.appname || 'Gameboard');
+ if (this.config.environment.settings.custom_background) {
+ this.document.body.classList.add(this.config.environment.settings.custom_background);
+ this.customBackground = this.config.environment.settings.custom_background || this.customBackground;
+ }
+
+ if (this.autoLogin.enabled && !this.autoLogin.tried && !await this.auth.isLoggedIn()) {
+ this.autoLogin.tried = true;
+ await this.auth.login();
}
}
}
diff --git a/projects/gameboard-ui/src/app/app.module.ts b/projects/gameboard-ui/src/app/app.module.ts
index 8d2f0d36..c1ddd806 100644
--- a/projects/gameboard-ui/src/app/app.module.ts
+++ b/projects/gameboard-ui/src/app/app.module.ts
@@ -34,6 +34,7 @@ import { GameboardSignalRHubsComponent } from './components/gameboard-signalr-hu
import { SignalRService } from './services/signalR/signalr.service';
import { LogService } from './services/log.service';
import { SystemNotificationsModule } from './system-notifications/system-notifications.module';
+import { UserNavItemComponent } from './standalone/user/components/user-nav-item/user-nav-item.component';
@NgModule({
declarations: [
@@ -59,6 +60,9 @@ import { SystemNotificationsModule } from './system-notifications/system-notific
ModalModule.forRoot(),
BsDropdownModule.forRoot(),
ProgressbarModule.forRoot(),
+
+ // standalones
+ UserNavItemComponent
],
providers: [
{
diff --git a/projects/gameboard-ui/src/app/components/nav/nav.component.html b/projects/gameboard-ui/src/app/components/nav/nav.component.html
index c19b2f7f..43f4387e 100644
--- a/projects/gameboard-ui/src/app/components/nav/nav.component.html
+++ b/projects/gameboard-ui/src/app/components/nav/nav.component.html
@@ -22,7 +22,7 @@
Admin
- Log out
+ Log out
@@ -71,7 +71,7 @@
- Log out
+ Log out
@@ -79,5 +79,5 @@
- Log in
+ Log in
diff --git a/projects/gameboard-ui/src/app/components/nav/nav.component.scss b/projects/gameboard-ui/src/app/components/nav/nav.component.scss
index ba775bd8..3cabc4d8 100644
--- a/projects/gameboard-ui/src/app/components/nav/nav.component.scss
+++ b/projects/gameboard-ui/src/app/components/nav/nav.component.scss
@@ -1,3 +1,5 @@
+@import "../../../scss/variables";
+
@media (max-width: 800px) {
.nav-sm {
display: flex;
@@ -5,7 +7,6 @@
.badge {
display: inline-block;
font-size: 0.5rem !important;
- // margin-right: 12px;
}
li {
@@ -27,9 +28,16 @@
display: block;
.nav-items {
- a {
+ a,
+ div[role="button"] {
display: block;
font-size: 1.5rem;
+
+ &.active {
+ color: $body-color !important;
+ font-weight: bolder;
+ text-decoration: underline;
+ }
}
}
diff --git a/projects/gameboard-ui/src/app/components/nav/nav.component.ts b/projects/gameboard-ui/src/app/components/nav/nav.component.ts
index dd96e260..465ce4cf 100644
--- a/projects/gameboard-ui/src/app/components/nav/nav.component.ts
+++ b/projects/gameboard-ui/src/app/components/nav/nav.component.ts
@@ -1,12 +1,13 @@
+import { Observable } from 'rxjs';
import { TocFile, TocService } from '@/api/toc.service';
import { ApiUser } from '@/api/user-models';
import { UserService as LocalUser } from '@/utility/user.service';
import { PracticeService } from '@/services/practice.service';
import { UnsubscriberService } from '@/services/unsubscriber.service';
-import { Component, OnInit } from '@angular/core';
-import { Observable } from 'rxjs';
-import { RouterService } from '@/services/router.service';
+import { Component, inject, OnInit } from '@angular/core';
import { fa } from '@/services/font-awesome.service';
+import { AuthService } from '@/utility/auth.service';
+import { RouterService } from '@/services/router.service';
@Component({
selector: 'app-nav',
@@ -15,6 +16,9 @@ import { fa } from '@/services/font-awesome.service';
providers: [UnsubscriberService]
})
export class AppNavComponent implements OnInit {
+ private authService = inject(AuthService);
+ private routerService = inject(RouterService);
+
user$!: Observable;
toc$!: Observable;
customBackground = "";
@@ -23,12 +27,11 @@ export class AppNavComponent implements OnInit {
protected fa = fa;
protected isCollapsed = false;
protected isPracticeModeEnabled = false;
- protected profileUrl?: string;
+ protected profileUrl = "";
constructor(
private localUser: LocalUser,
private practiceService: PracticeService,
- private routerService: RouterService,
private toc: TocService,
private unsub: UnsubscriberService
) { }
@@ -46,7 +49,11 @@ export class AppNavComponent implements OnInit {
this.isPracticeModeEnabled = isEnabled;
}
- logout(): void {
- this.localUser.logout();
+ protected async handleLogIn() {
+ await this.authService.login();
+ }
+
+ protected handleLogOut() {
+ this.authService.logout();
}
}
diff --git a/projects/gameboard-ui/src/app/components/sponsor-select-banner/sponsor-select-banner.component.ts b/projects/gameboard-ui/src/app/components/sponsor-select-banner/sponsor-select-banner.component.ts
index f880c1ad..16ca71bb 100644
--- a/projects/gameboard-ui/src/app/components/sponsor-select-banner/sponsor-select-banner.component.ts
+++ b/projects/gameboard-ui/src/app/components/sponsor-select-banner/sponsor-select-banner.component.ts
@@ -31,7 +31,7 @@ export class SponsorSelectBannerComponent {
localUserService: LocalUserService,
logService: LogService,
routerService: RouterService) {
- this.appName = config.settings.appname || this.appName;
+ this.appName = config.environment.settings.appname || this.appName;
this.profileUrl = routerService.getProfileUrl();
if (!this.profileUrl) {
diff --git a/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.scss b/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.scss
index d0edfce4..5d27884d 100644
--- a/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.scss
+++ b/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.scss
@@ -1,6 +1,11 @@
@use "sass:map";
@import "../../../../scss/player-avatars";
+:host {
+ display: flex;
+ align-items: center;
+}
+
.avatar-container {
aspect-ratio: 1 / 1;
background: no-repeat center center;
@@ -10,5 +15,4 @@
border-radius: 50%;
clip-path: circle(50% at 50% 50%);
display: inline-block;
- object-fit: cover;
}
diff --git a/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.ts b/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.ts
index 17acf94a..5960492d 100644
--- a/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.ts
+++ b/projects/gameboard-ui/src/app/core/components/avatar/avatar.component.ts
@@ -1,5 +1,6 @@
import { Component, ElementRef, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
import { SafeUrl } from '@angular/platform-browser';
+import { PlacementForBs5 } from 'ngx-bootstrap/positioning';
export type AvatarSize = 'tiny' | 'small' | 'medium' | 'large';
@@ -10,12 +11,13 @@ export type AvatarSize = 'tiny' | 'small' | 'medium' | 'large';
-
+
`,
})
export class AvatarComponent implements OnChanges {
@Input() imageUrl?: SafeUrl;
@Input() size: AvatarSize = "medium";
+ @Input() tooltipPlacement = PlacementForBs5.top;
@ViewChild("searchBox") searchBox?: ElementRef ;
diff --git a/projects/gameboard-ui/src/app/core/components/modal/modal-confirm.component.ts b/projects/gameboard-ui/src/app/core/components/modal/modal-confirm.component.ts
index 87f06f22..de698bbf 100644
--- a/projects/gameboard-ui/src/app/core/components/modal/modal-confirm.component.ts
+++ b/projects/gameboard-ui/src/app/core/components/modal/modal-confirm.component.ts
@@ -9,7 +9,7 @@ import { ModalConfirmConfig } from '@/core/components/modal/modal.models';