@@ -5,10 +5,10 @@ import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
55import { ProblemService } from '@/services/problem.service' ;
66import { toSignal } from '@angular/core/rxjs-interop' ;
77import { AuthService } from '@/services/auth.service' ;
8- import { map , combineLatest , Subject , startWith , defer , Observable } from 'rxjs' ;
8+ import { map , combineLatest , Subject , startWith , defer , Observable , filter } from 'rxjs' ;
99import { AsyncPipe } from '@angular/common' ;
1010import { formatDate } from '@/util' ;
11- import { LabelAnnotation } from '@/types' ;
11+ import { Label , LabelAnnotation } from '@/types' ;
1212
1313type SelectedLabelsForm = FormGroup < {
1414 problemId : FormControl < number > ;
@@ -47,55 +47,20 @@ export class ManageLabelsModalComponent implements OnInit {
4747 startWith ( this . form . controls . selectedLabelIds . value ) ,
4848 ) ) ;
4949
50- /** Combines selected IDs with existing annotations and all labels to show what's selected */
51- public shownLabels$ : Observable < LabelAnnotation [ ] > = combineLatest ( [
52- this . allLabels$ ,
50+ public allLabelsAndSelectedIds = combineLatest ( [
51+ this . allLabels$ . pipe ( filter ( labels => labels . length > 0 ) ) ,
5352 this . selectedLabelIds$
54- ] ) . pipe (
55- map ( ( [ allLabels , selectedIds ] ) => {
56- if ( ! allLabels ) {
57- return [ ] ;
58- }
59- // Show existing annotations that are still selected, plus new ones
60- return selectedIds . map ( labelId => {
61- const existing = this . currentAnnotations . find ( a => a . label . id === labelId ) ;
62- if ( existing ) {
63- return existing ;
64- }
65- // Create a simple display object for newly selected labels
66- const label = allLabels . find ( l => l . id === labelId ) ;
67- if ( ! label ) {
68- return null ;
69- }
70-
71- const newAnnotation : LabelAnnotation = {
72- id : null ,
73- label,
74- createdAt : new Date ( ) . toISOString ( ) ,
75- createdBy : this . currentUserName ( ) ?? $localize `Unknown user` ,
76- attachedByCurrentUser : true ,
77- session : null ,
78- removedAt : null ,
79- removedBy : null ,
80- notes : '' ,
81- removable : true ,
82-
83- } ;
84- return newAnnotation ;
85- } ) . filter ( ( a ) => a !== null ) ;
86- } )
53+ ] ) ;
54+
55+ /**
56+ * Turns selected label IDs into objects that are used in the template.
57+ */
58+ public shownLabels$ : Observable < LabelAnnotation [ ] > = this . allLabelsAndSelectedIds . pipe (
59+ map ( ( [ allLabels , selectedIds ] ) => this . convertSelectedIdsToAnnotations ( selectedIds , allLabels ) ) ,
8760 ) ;
8861
89- public availableLabels$ = combineLatest ( [
90- this . allLabels$ ,
91- this . selectedLabelIds$
92- ] ) . pipe (
93- map ( ( [ allLabels , selectedIds ] ) => {
94- if ( ! allLabels ) {
95- return [ ] ;
96- }
97- return allLabels . filter ( label => ! selectedIds . includes ( label . id ) ) ;
98- } )
62+ public availableLabels$ = this . allLabelsAndSelectedIds . pipe (
63+ map ( ( [ allLabels , selectedIds ] ) => allLabels . filter ( label => ! selectedIds . includes ( label . id ) ) ) ,
9964 ) ;
10065
10166 public loadingLabels$ = this . availableLabels$ . pipe (
@@ -146,4 +111,42 @@ export class ManageLabelsModalComponent implements OnInit {
146111 private currentUserName = toSignal (
147112 this . authService . currentUser$ . pipe ( map ( ( user ) => user ?. username ) )
148113 ) ;
114+
115+ private convertSelectedIdsToAnnotations ( selectedIds : number [ ] , allLabels : Label [ ] ) : LabelAnnotation [ ] {
116+ const existingAnnotationMap = new Map (
117+ this . currentAnnotations . map ( a => [ a . label . id , a ] )
118+ ) ;
119+ const allLabelsMap = new Map ( allLabels . map ( l => [ l . id , l ] ) ) ;
120+ const currentUser = this . currentUserName ( ) ?? $localize `Unknown user` ;
121+
122+ return selectedIds . map ( labelId => {
123+ // Try to find existing annotation first
124+ const existing = existingAnnotationMap . get ( labelId ) ;
125+ if ( existing ) {
126+ return existing ;
127+ }
128+
129+ return this . createAnnotationForId ( labelId , allLabelsMap , currentUser ) ;
130+ } ) . filter ( annotation => annotation !== null ) ;
131+ }
132+
133+ private createAnnotationForId ( labelId : number , allLabels : Map < number , Label > , currentUser : string ) : LabelAnnotation | null {
134+ const label = allLabels . get ( labelId ) ;
135+ if ( ! label ) {
136+ return null ;
137+ }
138+
139+ return {
140+ id : null ,
141+ label,
142+ createdAt : new Date ( ) . toISOString ( ) ,
143+ createdBy : currentUser ,
144+ attachedByCurrentUser : true ,
145+ session : null ,
146+ removedAt : null ,
147+ removedBy : null ,
148+ notes : '' ,
149+ removable : true ,
150+ } as LabelAnnotation ;
151+ }
149152}
0 commit comments