• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geonetwork / geonetwork-ui / 13238047273

10 Feb 2025 09:51AM UTC coverage: 83.982% (+0.01%) from 83.972%
13238047273

Pull #1107

github

web-flow
Merge 04bd352b3 into 9ee0df3df
Pull Request #1107: Save records on creation/duplication and allow attachments

3294 of 4404 branches covered (74.8%)

Branch coverage included in aggregate %.

53 of 58 new or added lines in 15 files covered. (91.38%)

1 existing line in 1 file now uncovered.

9436 of 10754 relevant lines covered (87.74%)

275.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.32
/apps/metadata-editor/src/app/edit/edit-page.component.ts
1
import { CommonModule } from '@angular/common'
3✔
2
import {
3✔
3
  Component,
4
  ElementRef,
5
  OnDestroy,
6
  OnInit,
7
  ViewChild,
8
} from '@angular/core'
9
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'
3✔
10
import { ActivatedRoute, Router } from '@angular/router'
3✔
11
import { marker } from '@biesbjerg/ngx-translate-extract-marker'
3✔
12
import { PublicationVersionError } from '@geonetwork-ui/common/domain/model/error'
3✔
13
import {
3✔
14
  EditorFacade,
15
  RecordFormComponent,
16
} from '@geonetwork-ui/feature/editor'
17
import {
3✔
18
  NotificationsContainerComponent,
19
  NotificationsService,
20
} from '@geonetwork-ui/feature/notifications'
21
import { ButtonComponent } from '@geonetwork-ui/ui/inputs'
3✔
22
import { TranslateModule, TranslateService } from '@ngx-translate/core'
3✔
23
import { combineLatest, filter, firstValueFrom, Subscription, take } from 'rxjs'
3✔
24
import { map, skip } from 'rxjs/operators'
3✔
25
import { SidebarComponent } from '../dashboard/sidebar/sidebar.component'
3✔
26
import { PageSelectorComponent } from './components/page-selector/page-selector.component'
3✔
27
import { TopToolbarComponent } from './components/top-toolbar/top-toolbar.component'
3✔
28
import { SpinningLoaderComponent } from '@geonetwork-ui/ui/widgets'
3✔
29

30
marker('editor.record.form.bottomButtons.comeBackLater')
3✔
31
marker('editor.record.form.bottomButtons.previous')
3✔
32
marker('editor.record.form.bottomButtons.next')
3✔
33

34
@Component({
35
  selector: 'md-editor-edit',
36
  templateUrl: './edit-page.component.html',
37
  styleUrls: ['./edit-page.component.css'],
38
  standalone: true,
39
  imports: [
40
    RecordFormComponent,
41
    CommonModule,
42
    ButtonComponent,
43
    MatProgressSpinnerModule,
44
    TopToolbarComponent,
45
    NotificationsContainerComponent,
46
    PageSelectorComponent,
47
    TranslateModule,
48
    SidebarComponent,
49
    SpinningLoaderComponent,
50
  ],
51
})
52
export class EditPageComponent implements OnInit, OnDestroy {
3✔
53
  subscription = new Subscription()
12✔
54

55
  currentPage$ = this.facade.currentPage$
12✔
56
  pagesLength$ = this.facade.editorConfig$.pipe(
12✔
57
    map((config) => config.pages.length)
9✔
58
  )
59
  isLastPage$ = combineLatest([this.currentPage$, this.pagesLength$]).pipe(
12✔
60
    map(([currentPage, pagesCount]) => currentPage >= pagesCount - 1)
9✔
61
  )
62
  hasRecordChanged$ = this.facade.hasRecordChanged$.pipe(skip(1))
12✔
63

64
  newRecord = false
12✔
65
  isLoading = true
12✔
66

67
  @ViewChild('scrollContainer') scrollContainer: ElementRef<HTMLElement>
68

69
  constructor(
70
    private route: ActivatedRoute,
12!
71
    private facade: EditorFacade,
12!
72
    private notificationsService: NotificationsService,
12!
73
    private translateService: TranslateService,
12!
74
    private router: Router
12✔
75
  ) {}
76

77
  ngOnInit(): void {
78
    const [currentRecord, currentRecordSource] =
79
      this.route.snapshot.data['record']
10✔
80

81
    this.facade.openRecord(currentRecord, currentRecordSource)
10✔
82

83
    this.subscription.add(
10✔
84
      this.facade.record$.pipe(take(1)).subscribe((record) => {
85
        if (!record.uniqueIdentifier) {
10✔
86
          this.newRecord = true
1✔
87
          this.facade.saveRecord()
1✔
88
        } else {
89
          this.isLoading = false
9✔
90
        }
91
      })
92
    )
93

94
    this.subscription.add(
10✔
95
      this.facade.saveError$.subscribe((error) => {
96
        if (error instanceof PublicationVersionError) {
2✔
97
          this.notificationsService.showNotification(
1✔
98
            {
99
              type: 'error',
100
              title: this.translateService.instant(
101
                'editor.record.publishVersionError.title'
102
              ),
103
              text: this.translateService.instant(
104
                'editor.record.publishVersionError.body',
105
                { currentVersion: error.detectedApiVersion }
106
              ),
107
              closeMessage: this.translateService.instant(
108
                'editor.record.publishVersionError.closeMessage'
109
              ),
110
            },
111
            undefined,
112
            error
113
          )
114
        } else {
115
          this.notificationsService.showNotification(
1✔
116
            {
117
              type: 'error',
118
              title: this.translateService.instant(
119
                'editor.record.publishError.title'
120
              ),
121
              text: `${this.translateService.instant(
122
                'editor.record.publishError.body'
123
              )} ${error.message}`,
124
              closeMessage: this.translateService.instant(
125
                'editor.record.publishError.closeMessage'
126
              ),
127
            },
128
            undefined,
129
            error
130
          )
131
        }
132
      })
133
    )
134

135
    this.subscription.add(
10✔
136
      this.facade.saveSuccess$.subscribe(() => {
137
        if (!this.newRecord) {
1✔
138
          this.notificationsService.showNotification(
1✔
139
            {
140
              type: 'success',
141
              title: this.translateService.instant(
142
                'editor.record.publishSuccess.title'
143
              ),
144
              text: `${this.translateService.instant(
145
                'editor.record.publishSuccess.body'
146
              )}`,
147
            },
148
            2500
149
          )
150
        }
151
      })
152
    )
153

154
    this.subscription.add(
10✔
155
      this.facade.record$.subscribe((record) => {
156
        this.facade.checkHasRecordChanged(record)
11✔
157
      })
158
    )
159

160
    // if we're on the /duplicate route, go to /edit/{uuid} to update the uuid
161
    if (this.route.snapshot.routeConfig?.path.includes('duplicate')) {
10!
NEW
162
      this.router.navigate(['edit', currentRecord.uniqueIdentifier], {
×
163
        replaceUrl: true,
164
      })
165
    }
166

167
    // if the record unique identifier changes, navigate to /edit/newUuid
168
    this.subscription.add(
10✔
169
      this.facade.record$
170
        .pipe(
171
          filter(
172
            (record) =>
173
              record?.uniqueIdentifier !== currentRecord.uniqueIdentifier
10✔
174
          ),
175
          take(1)
176
        )
177
        .subscribe((savedRecord) => {
178
          this.router.navigate(['edit', savedRecord.uniqueIdentifier], {
2✔
179
            replaceUrl: true,
180
          })
181
        })
182
    )
183
  }
184

185
  ngOnDestroy() {
186
    this.subscription.unsubscribe()
13✔
187
  }
188

189
  async previousPageButtonHandler() {
190
    const currentPage = await firstValueFrom(this.currentPage$)
×
191
    if (currentPage === 0) {
×
192
      this.router.navigate(['catalog', 'search'])
×
193
    } else {
194
      this.facade.setCurrentPage(currentPage - 1)
×
195
      this.scrollToTop()
×
196
    }
197
  }
198

199
  async nextPageButtonHandler() {
200
    const currentPage = await firstValueFrom(this.currentPage$)
×
201
    const pagesCount = await firstValueFrom(this.pagesLength$)
×
202
    if (currentPage < pagesCount - 1) {
×
203
      this.facade.setCurrentPage(currentPage + 1)
×
204
      this.scrollToTop()
×
205
    }
206
  }
207

208
  private scrollToTop() {
209
    this.scrollContainer.nativeElement.scroll({
×
210
      behavior: 'instant',
211
      top: 0,
212
    })
213
  }
214

215
  formatDate(date: Date): string {
216
    return date.toLocaleDateString(this.translateService.currentLang, {
×
217
      year: 'numeric',
218
      month: 'long',
219
      day: 'numeric',
220
      hour: 'numeric',
221
      minute: 'numeric',
222
    })
223
  }
224
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc