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

geonetwork / geonetwork-ui / 13396961924

18 Feb 2025 05:52PM UTC coverage: 82.537%. First build
13396961924

Pull #1123

github

web-flow
Merge 4468f56c8 into 6410b21c8
Pull Request #1123: DateService for consistent locale-based date formatting

2468 of 3401 branches covered (72.57%)

Branch coverage included in aggregate %.

37 of 39 new or added lines in 7 files covered. (94.87%)

7462 of 8630 relevant lines covered (86.47%)

11.69 hits per line

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

78.1
/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
import { SearchHeaderComponent } from '../dashboard/search-header/search-header.component'
3✔
30
import { PageErrorComponent } from './components/page-error/page-error.component'
3✔
31
import { DateService } from '@geonetwork-ui/util/shared'
3✔
32

33
marker('editor.record.form.bottomButtons.comeBackLater')
3✔
34
marker('editor.record.form.bottomButtons.previous')
3✔
35
marker('editor.record.form.bottomButtons.next')
3✔
36

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

60
  currentPage$ = this.facade.currentPage$
12✔
61
  pagesLength$ = this.facade.editorConfig$.pipe(
12✔
62
    map((config) => config.pages.length)
2✔
63
  )
64
  isLastPage$ = combineLatest([this.currentPage$, this.pagesLength$]).pipe(
12✔
65
    map(([currentPage, pagesCount]) => currentPage >= pagesCount - 1)
2✔
66
  )
67
  hasRecordChanged$ = this.facade.hasRecordChanged$.pipe(skip(1))
12✔
68

69
  newRecord = false
12✔
70
  isLoading = true
12✔
71

72
  @ViewChild('scrollContainer') scrollContainer: ElementRef<HTMLElement>
73

74
  constructor(
75
    private route: ActivatedRoute,
12!
76
    protected facade: EditorFacade,
12!
77
    private notificationsService: NotificationsService,
12!
78
    private translateService: TranslateService,
12!
79
    private router: Router,
12!
80
    private dateService: DateService
12✔
81
  ) {}
82

83
  ngOnInit(): void {
84
    const [currentRecord, currentRecordSource] =
85
      this.route.snapshot.data['record']
10✔
86

87
    this.facade.openRecord(currentRecord, currentRecordSource)
10✔
88

89
    this.subscription.add(
10✔
90
      this.facade.record$.pipe(take(1)).subscribe((record) => {
91
        if (!record.uniqueIdentifier) {
10✔
92
          this.newRecord = true
1✔
93
          this.facade.saveRecord()
1✔
94
        } else {
95
          this.isLoading = false
9✔
96
        }
97
      })
98
    )
99

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

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

160
    this.subscription.add(
10✔
161
      this.facade.record$.subscribe((record) => {
162
        this.facade.checkHasRecordChanged(record)
11✔
163
      })
164
    )
165

166
    // if we're on the /duplicate route, go to /edit/{uuid} to update the uuid
167
    if (this.route.snapshot.routeConfig?.path.includes('duplicate')) {
10!
168
      this.router.navigate(['edit', currentRecord.uniqueIdentifier], {
×
169
        replaceUrl: true,
170
      })
171
    }
172

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

191
  ngOnDestroy() {
192
    this.subscription.unsubscribe()
13✔
193
  }
194

195
  async previousPageButtonHandler() {
196
    const currentPage = await firstValueFrom(this.currentPage$)
×
197
    if (currentPage === 0) {
×
198
      this.router.navigate(['catalog', 'search'])
×
199
    } else {
200
      this.facade.setCurrentPage(currentPage - 1)
×
201
      this.scrollToTop()
×
202
    }
203
  }
204

205
  async nextPageButtonHandler() {
206
    const currentPage = await firstValueFrom(this.currentPage$)
×
207
    const pagesCount = await firstValueFrom(this.pagesLength$)
×
208
    if (currentPage < pagesCount - 1) {
×
209
      this.facade.setCurrentPage(currentPage + 1)
×
210
      this.scrollToTop()
×
211
    }
212
  }
213

214
  private scrollToTop() {
215
    this.scrollContainer.nativeElement.scroll({
×
216
      behavior: 'instant',
217
      top: 0,
218
    })
219
  }
220

221
  formatDate(date: Date): string {
NEW
222
    return this.dateService.formatDate(date, {
×
223
      year: 'numeric',
224
      month: 'long',
225
      day: 'numeric',
226
      hour: 'numeric',
227
      minute: 'numeric',
228
    })
229
  }
230
}
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