AI Implementation feature(841): First-Start Create Admin Modal 1.00 (#3)
This commit was merged in pull request #3.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
OnInit,
|
||||
inject,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AdminService, AdminUser } from '../../core/services/admin.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-admin-users',
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
imports: [CommonModule],
|
||||
template: `
|
||||
<section class="admin-area">
|
||||
<h2>Admin area</h2>
|
||||
<p data-testid="admin-loading" *ngIf="loading()">Loading users...</p>
|
||||
<p data-testid="admin-error" *ngIf="error()" style="color:var(--color-danger)">{{ error() }}</p>
|
||||
<ul data-testid="admin-user-list" *ngIf="!loading() && !error()">
|
||||
<li *ngFor="let u of users()">
|
||||
<b>{{ u.username }}</b> ({{ u.role }})
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
`,
|
||||
})
|
||||
export class AdminUsersComponent implements OnInit {
|
||||
private readonly admin = inject(AdminService);
|
||||
|
||||
readonly users = signal<AdminUser[]>([]);
|
||||
readonly loading = signal(false);
|
||||
readonly error = signal<string | null>(null);
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.loading.set(true);
|
||||
this.error.set(null);
|
||||
try {
|
||||
const list = await this.admin.listUsers();
|
||||
this.users.set(list);
|
||||
} catch (e: any) {
|
||||
this.error.set(e?.error?.message ?? e?.message ?? 'Failed to load users');
|
||||
} finally {
|
||||
this.loading.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,47 @@
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { Component, computed, inject } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { BootstrapService } from '../../core/services/bootstrap.service';
|
||||
import { AuthService } from '../../core/services/auth.service';
|
||||
import { shouldShowAdminNav } from './home.shell';
|
||||
|
||||
export { shouldShowAdminNav } from './home.shell';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
imports: [CommonModule, RouterLink, RouterOutlet],
|
||||
template: `
|
||||
<div class="container">
|
||||
<h1>{{ bootstrap.payload()?.pageTitle ?? 'HIPCTF' }}</h1>
|
||||
<div *ngIf="!auth.isAuthenticated()">
|
||||
<p>{{ bootstrap.payload()?.welcomeMarkdown }}</p>
|
||||
<a href="/login">Sign in</a>
|
||||
</div>
|
||||
<div *ngIf="auth.isAuthenticated()">
|
||||
<p>Signed in as <b>{{ auth.currentUser()?.username }}</b> ({{ auth.currentUser()?.role }})</p>
|
||||
</div>
|
||||
<header class="shell-header">
|
||||
<h1 class="shell-title">{{ bootstrap.payload()?.pageTitle ?? 'HIPCTF' }}</h1>
|
||||
<div class="shell-user" *ngIf="auth.isAuthenticated()">
|
||||
<span>Signed in as <b>{{ auth.currentUser()?.username }}</b> ({{ auth.currentUser()?.role }})</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="shell-nav" *ngIf="showAdminNav()">
|
||||
<a routerLink="/admin" data-testid="nav-admin">Admin</a>
|
||||
</nav>
|
||||
|
||||
<section class="shell-body">
|
||||
<div *ngIf="!auth.isAuthenticated()">
|
||||
<p>{{ bootstrap.payload()?.welcomeMarkdown }}</p>
|
||||
<a href="/login">Sign in</a>
|
||||
</div>
|
||||
<router-outlet></router-outlet>
|
||||
</section>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class HomeComponent {
|
||||
bootstrap = inject(BootstrapService);
|
||||
auth = inject(AuthService);
|
||||
}
|
||||
|
||||
readonly showAdminNav = computed(() =>
|
||||
shouldShowAdminNav({
|
||||
isAuthenticated: this.auth.isAuthenticated(),
|
||||
role: this.auth.currentUser()?.role,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
export function shouldShowAdminNav(input: {
|
||||
isAuthenticated: boolean;
|
||||
role: 'admin' | 'player' | undefined;
|
||||
}): boolean {
|
||||
return input.isAuthenticated && input.role === 'admin';
|
||||
}
|
||||
@@ -102,7 +102,7 @@ export class SetupCreateAdminComponent {
|
||||
if (result.ok) {
|
||||
this.auth.setSession(result.accessToken, result.user);
|
||||
this.bootstrap.markInitialized();
|
||||
await this.router.navigateByUrl('/challenges');
|
||||
await this.router.navigateByUrl('/admin');
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user