feat: NCWF-5/6/7/8/9 chess analysis page and engine integration
- NCWF-5: scaffold /analysis route with ChessBoard viewer and navigation - NCWF-6: FEN / PGN / Game-ID input form with depth selector - NCWF-7: extend GameApiService with analyzePosition(); add AnalysisService with game-wide annotation pipeline; proxy /api/analysis -> :8087 - NCWF-8: EvalTimelineComponent — SVG win-chance chart per ply - NCWF-9: AnnotatedMoveListComponent — quality labels (!! ! ?! ? ??) derived from win-chance delta Also fix pre-existing app.spec.ts failure (missing provideHttpClient). Apply project-wide prettier formatting pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,71 +8,71 @@ import { Challenge } from '../models/challenge.models';
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ChallengeEventService {
|
||||
private readonly incomingChallenges$ = new BehaviorSubject<Challenge[]>([]);
|
||||
private readonly challengeReceived$ = new Subject<Challenge>();
|
||||
private readonly challengeAccepted$ = new Subject<Challenge>();
|
||||
private readonly challengeDeclined$ = new Subject<Challenge>();
|
||||
private readonly incomingChallenges$ = new BehaviorSubject<Challenge[]>([]);
|
||||
private readonly challengeReceived$ = new Subject<Challenge>();
|
||||
private readonly challengeAccepted$ = new Subject<Challenge>();
|
||||
private readonly challengeDeclined$ = new Subject<Challenge>();
|
||||
|
||||
getIncomingChallenges$(): Observable<Challenge[]> {
|
||||
return this.incomingChallenges$.asObservable();
|
||||
}
|
||||
getIncomingChallenges$(): Observable<Challenge[]> {
|
||||
return this.incomingChallenges$.asObservable();
|
||||
}
|
||||
|
||||
getChallengeReceived$(): Observable<Challenge> {
|
||||
return this.challengeReceived$.asObservable();
|
||||
}
|
||||
getChallengeReceived$(): Observable<Challenge> {
|
||||
return this.challengeReceived$.asObservable();
|
||||
}
|
||||
|
||||
getChallengeAccepted$(): Observable<Challenge> {
|
||||
return this.challengeAccepted$.asObservable();
|
||||
}
|
||||
getChallengeAccepted$(): Observable<Challenge> {
|
||||
return this.challengeAccepted$.asObservable();
|
||||
}
|
||||
|
||||
getChallengeDeclined$(): Observable<Challenge> {
|
||||
return this.challengeDeclined$.asObservable();
|
||||
}
|
||||
getChallengeDeclined$(): Observable<Challenge> {
|
||||
return this.challengeDeclined$.asObservable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new challenge is received via WebSocket
|
||||
*/
|
||||
onChallengeReceived(challenge: Challenge): void {
|
||||
const current = this.incomingChallenges$.value;
|
||||
this.incomingChallenges$.next([...current, challenge]);
|
||||
this.challengeReceived$.next(challenge);
|
||||
}
|
||||
/**
|
||||
* Called when a new challenge is received via WebSocket
|
||||
*/
|
||||
onChallengeReceived(challenge: Challenge): void {
|
||||
const current = this.incomingChallenges$.value;
|
||||
this.incomingChallenges$.next([...current, challenge]);
|
||||
this.challengeReceived$.next(challenge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a challenge is accepted
|
||||
*/
|
||||
onChallengeAccepted(challenge: Challenge): void {
|
||||
const current = this.incomingChallenges$.value;
|
||||
this.incomingChallenges$.next(current.filter(c => c.id !== challenge.id));
|
||||
this.challengeAccepted$.next(challenge);
|
||||
}
|
||||
/**
|
||||
* Called when a challenge is accepted
|
||||
*/
|
||||
onChallengeAccepted(challenge: Challenge): void {
|
||||
const current = this.incomingChallenges$.value;
|
||||
this.incomingChallenges$.next(current.filter((c) => c.id !== challenge.id));
|
||||
this.challengeAccepted$.next(challenge);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a challenge is declined or expires
|
||||
*/
|
||||
onChallengeRemoved(challengeId: string): void {
|
||||
const current = this.incomingChallenges$.value;
|
||||
this.incomingChallenges$.next(current.filter(c => c.id !== challengeId));
|
||||
}
|
||||
/**
|
||||
* Called when a challenge is declined or expires
|
||||
*/
|
||||
onChallengeRemoved(challengeId: string): void {
|
||||
const current = this.incomingChallenges$.value;
|
||||
this.incomingChallenges$.next(current.filter((c) => c.id !== challengeId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a challenge from the incoming list
|
||||
*/
|
||||
removeChallenge(challengeId: string): void {
|
||||
this.onChallengeRemoved(challengeId);
|
||||
}
|
||||
/**
|
||||
* Remove a challenge from the incoming list
|
||||
*/
|
||||
removeChallenge(challengeId: string): void {
|
||||
this.onChallengeRemoved(challengeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the full incoming list (used by HTTP polling)
|
||||
*/
|
||||
setIncomingChallenges(challenges: Challenge[]): void {
|
||||
this.incomingChallenges$.next(challenges);
|
||||
}
|
||||
/**
|
||||
* Replace the full incoming list (used by HTTP polling)
|
||||
*/
|
||||
setIncomingChallenges(challenges: Challenge[]): void {
|
||||
this.incomingChallenges$.next(challenges);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all incoming challenges (used on logout)
|
||||
*/
|
||||
clear(): void {
|
||||
this.incomingChallenges$.next([]);
|
||||
}
|
||||
/**
|
||||
* Clear all incoming challenges (used on logout)
|
||||
*/
|
||||
clear(): void {
|
||||
this.incomingChallenges$.next([]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user