Skip to content

Commit

Permalink
Merge pull request #909 from geonetwork/me-add-graphical-overview-rec…
Browse files Browse the repository at this point in the history
…ord-field

EDITOR - Record field: graphic overview
  • Loading branch information
LHBruneton-C2C authored Aug 9, 2024
2 parents 8118add + 2a38a00 commit e079151
Show file tree
Hide file tree
Showing 22 changed files with 319 additions and 119 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
<gn-ui-image-input
[maxSizeMB]="5"
[previewUrl]="resourceUrl"
[altText]="resourceFileName"
[altText]="resourceAltText"
[formControl]="formControl"
(fileChange)="handleFileChange($event)"
(urlChange)="handleUrlChange($event)"
(altTextChange)="handleAltTextChange($event)"
(delete)="handleDelete()"
></gn-ui-image-input>
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,27 @@ import { TranslateModule } from '@ngx-translate/core'
import { of } from 'rxjs'
import { OverviewUploadComponent } from './overview-upload.component'

const imageFileName = 'doge.jpg'
const imageUrl =
'http://localhost:8080/geonetwork/srv/api/records/8698bf0b-fceb-4f0f-989b-111e7c4af0a4/attachments/doge.jpg'

class RecordsApiServiceMock {
getAllResources = jest.fn(() =>
of([{ filename: 'filenameGet', url: 'urlGet' }])
of([
{
filename: imageFileName,
url: imageUrl,
},
])
)
putResource = jest.fn(() =>
of({
filename: imageFileName,
url: imageUrl,
})
)
putResource = jest.fn(() => of({ filename: 'filenamePut', url: 'urlPut' }))
putResourceFromURL = jest.fn(() =>
of({ filename: 'filenamePutUrl', url: 'urlPutUrl' })
of({ filename: imageFileName, url: imageUrl })
)
delResource = jest.fn(() => of(void 0))
}
Expand Down Expand Up @@ -50,9 +64,11 @@ describe('OverviewUploadComponent', () => {
})

it('should get all resources corresponding to the metadata UUID on init', () => {
fixture.detectChanges()
expect(recordsApiService.getAllResources).toHaveBeenCalledWith(metadataUuid)
expect(component.resourceFileName).toEqual('filenameGet')
expect(component.resourceUrl).toEqual('urlGet')
expect(component.resourceAltText).toEqual(imageFileName)
expect(component.resourceFileName).toEqual(imageFileName)
expect(component.resourceUrl.href).toEqual(imageUrl)
})

it('should put the file resource on file change', () => {
Expand All @@ -63,8 +79,22 @@ describe('OverviewUploadComponent', () => {
someFile,
'public'
)
expect(component.resourceFileName).toEqual('filenamePut')
expect(component.resourceUrl).toEqual('urlPut')
expect(component.resourceAltText).toEqual(imageFileName)
expect(component.resourceUrl.href).toEqual(imageUrl)
})

it('should put the file resource on alt text change', () => {
const altTextChangeSpy = jest.spyOn(component.overviewChange, 'emit')

const newAltText = 'newAltText'
const newImageUrl = new URL(imageUrl)

component.handleAltTextChange(newAltText)
expect(altTextChangeSpy).toHaveBeenCalledWith({
description: newAltText,
url: newImageUrl,
})
expect(component.resourceAltText).toEqual('newAltText')
})

it('should put the resource from URL on URL change', () => {
Expand All @@ -74,18 +104,18 @@ describe('OverviewUploadComponent', () => {
'someUrl',
'public'
)
expect(component.resourceFileName).toEqual('filenamePutUrl')
expect(component.resourceUrl).toEqual('urlPutUrl')
expect(component.resourceAltText).toEqual(imageFileName)
expect(component.resourceUrl.href).toEqual(imageUrl)
})

it('should delete the resource corresponding to the metadata UUID on delete', () => {
component.resourceFileName = 'filenameDelete'
component.resourceAltText = 'filenameDelete'
component.handleDelete()
expect(recordsApiService.delResource).toHaveBeenCalledWith(
metadataUuid,
'filenameDelete'
imageFileName
)
expect(component.resourceFileName).toBeNull()
expect(component.resourceAltText).toBeNull()
expect(component.resourceUrl).toBeNull()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,24 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
SimpleChanges,
} from '@angular/core'
import { CommonModule } from '@angular/common'
import { RecordsApiService } from '@geonetwork-ui/data-access/gn4'
import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
import { FormControl } from '@angular/forms'
import { GraphicOverview } from '@geonetwork-ui/common/domain/model/record'

const extractFileNameFromUrl = (url: string): string => {
const pattern = new RegExp(`attachments/([^/?#]+)(?:[/?#]|$)`, 'i')
const match = url.match(pattern)
return match ? match[1] : ''
}

@Component({
selector: 'gn-ui-overview-upload',
Expand All @@ -17,54 +29,138 @@ import { UiInputsModule } from '@geonetwork-ui/ui/inputs'
styleUrls: ['./overview-upload.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class OverviewUploadComponent implements OnInit {
export class OverviewUploadComponent implements OnInit, OnChanges {
@Input() metadataUuid: string
@Input() formControl!: FormControl
@Output() overviewChange = new EventEmitter<GraphicOverview | null>()
@Output() altTextChange: EventEmitter<string> = new EventEmitter()

resourceFileName: string
resourceUrl: string
resourceAltText = '' // = ressourceFileName by default
resourceFileName = ''
resourceUrl: URL

constructor(
private recordsApiService: RecordsApiService,
private cd: ChangeDetectorRef
) {}

ngOnInit(): void {
this.recordsApiService
.getAllResources(this.metadataUuid)
.subscribe((resources) => {
this.resourceFileName = resources[0]?.filename
this.resourceUrl = resources[0]?.url
this.recordsApiService.getAllResources(this.metadataUuid).subscribe({
next: (resources) => {
if (resources && resources.length > 0) {
this.resourceUrl = new URL(resources[0]?.url)
this.resourceAltText =
this.resourceAltText === ''
? resources[0].filename
: this.resourceAltText
this.resourceFileName = extractFileNameFromUrl(resources[0]?.url)
} else {
this.resourceUrl = null
this.resourceAltText = ''
this.resourceFileName = ''
}

this.cd.markForCheck()
})
},
error: this.errorHandle,
})
}

handleFileChange(file: File) {
this.recordsApiService
.putResource(this.metadataUuid, file, 'public')
.subscribe((resource) => {
this.resourceFileName = resource.filename
this.resourceUrl = resource.url
this.cd.markForCheck()
.subscribe({
next: (resource) => {
this.resourceUrl = new URL(resource.url)
this.resourceAltText = resource.filename

this.overviewChange.emit({
url: new URL(resource.url),
description: resource.filename,
})

this.cd.markForCheck()
},
error: this.errorHandle,
})
}

handleUrlChange(url: string) {
this.recordsApiService
.putResourceFromURL(this.metadataUuid, url, 'public')
.subscribe((resource) => {
this.resourceFileName = resource.filename
this.resourceUrl = resource.url
this.cd.markForCheck()
.subscribe({
next: (resource) => {
this.resourceUrl = new URL(resource.url)
this.resourceAltText = resource.filename

this.overviewChange.emit({
url: new URL(resource.url),
description: resource.filename,
})

this.cd.markForCheck()
},
error: this.errorHandle,
})
}

handleAltTextChange(newAltText: string) {
this.resourceAltText = newAltText

this.overviewChange.emit({
url: this.resourceUrl,
description: this.resourceAltText,
})
this.cd.markForCheck()
}

handleDelete() {
this.recordsApiService
.delResource(this.metadataUuid, this.resourceFileName)
.subscribe(() => {
this.resourceFileName = null
this.resourceUrl = null
this.cd.markForCheck()
.subscribe({
next: () => {
this.resourceAltText = null
this.resourceUrl = null

this.overviewChange.emit(null)

this.cd.markForCheck()
},
error: this.errorHandle,
})
}

private errorHandle = (error: never) => {
console.error(error)

this.resourceUrl = null
this.resourceAltText = ''
this.resourceFileName = ''

this.overviewChange.emit(null)

this.cd.markForCheck()
}

ngOnChanges(changes: SimpleChanges): void {
const overviewChanges = changes['formControl']
if (
overviewChanges &&
overviewChanges.currentValue !== overviewChanges.previousValue
) {
let overview: GraphicOverview
if (
overviewChanges.currentValue.value &&
overviewChanges.currentValue.value.length > 0
) {
overview = overviewChanges.currentValue.value[0] as GraphicOverview
} else {
return
}
if (overview.description && overview.description !== '') {
this.resourceAltText = overview.description
this.cd.markForCheck()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<gn-ui-overview-upload
[metadataUuid]="metadataUuid"
[formControl]="control"
(overviewChange)="handleOverviewChange($event)"
></gn-ui-overview-upload>
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { FormFieldOverviewsComponent } from './form-field-overviews.component'
import { HttpClientTestingModule } from '@angular/common/http/testing'
import { TranslateModule } from '@ngx-translate/core'
import { FormControl } from '@angular/forms'

describe('FormFieldOverviewsComponent', () => {
let component: FormFieldOverviewsComponent
let fixture: ComponentFixture<FormFieldOverviewsComponent>

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
FormFieldOverviewsComponent,
HttpClientTestingModule,
TranslateModule.forRoot(),
],
}).compileComponents()

fixture = TestBed.createComponent(FormFieldOverviewsComponent)
component = fixture.componentInstance
component.metadataUuid = '8505d991-e38f-4704-a47a-e7d335dfbef5'
const control = new FormControl()
control.setValue([
{
description: 'doge.jpg',
url: new URL(
'http://localhost:8080/geonetwork/srv/api/0.1/records/8505d991-e38f-4704-a47a-e7d335dfbef5/attachments/doge.jpg'
),
},
])
component.control = control
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, Input } from '@angular/core'
import { OverviewUploadComponent } from '../../../overview-upload/overview-upload.component'
import { FormControl } from '@angular/forms'
import { GraphicOverview } from '@geonetwork-ui/common/domain/model/record'

@Component({
selector: 'gn-ui-form-field-overviews',
templateUrl: './form-field-overviews.component.html',
styleUrls: ['./form-field-overviews.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [CommonModule, OverviewUploadComponent],
})
export class FormFieldOverviewsComponent {
@Input() metadataUuid: string
@Input() control!: FormControl

handleOverviewChange(overView: GraphicOverview | null) {
this.control.setValue(overView ? [overView] : [])
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@
<ng-container *ngIf="isSpatialExtentField">
<gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>
</ng-container>
<ng-container *ngIf="isGraphicOverview">
<gn-ui-form-field-overviews
[control]="formControl"
[metadataUuid]="metadataUuid$ | async"
></gn-ui-form-field-overviews>
</ng-container>
<ng-container *ngIf="isKeywords">
<gn-ui-form-field-keywords
[control]="formControl"
Expand Down
Loading

0 comments on commit e079151

Please sign in to comment.