diff --git a/apps/metadata-editor-e2e/src/e2e/edit.cy.ts b/apps/metadata-editor-e2e/src/e2e/edit.cy.ts
index c6492c2616..50b910434e 100644
--- a/apps/metadata-editor-e2e/src/e2e/edit.cy.ts
+++ b/apps/metadata-editor-e2e/src/e2e/edit.cy.ts
@@ -402,6 +402,85 @@ describe('editor form', () => {
})
})
})
+ describe('distribution resources', () => {
+ beforeEach(() => {
+ cy.get('@resourcePageBtn').click()
+ })
+ it('adds a resource', () => {
+ // item count before adding
+ cy.get(
+ 'gn-ui-form-field-online-resources gn-ui-online-resource-card'
+ ).should('have.length', 0)
+ cy.editor_wrapPreviousDraft()
+ // add a service distribution
+ cy.get('[data-cy="online-resources-type"] button').eq(1).click()
+ cy.get('gn-ui-online-service-resource-input mat-radio-button')
+ .contains('WMS')
+ .click()
+ cy.get('gn-ui-online-service-resource-input')
+ .find('[data-cy="identifier-in-service"]')
+ .type('A layer name as identifier in service')
+ cy.get('gn-ui-form-field-online-resources')
+ .find('gn-ui-url-input')
+ .find('input')
+ .type('http://example.com/wms')
+ cy.get('gn-ui-form-field-online-resources')
+ .find('gn-ui-url-input')
+ .find('button')
+ .click()
+ cy.editor_publishAndReload()
+ cy.get('@saveStatus').should('eq', 'record_up_to_date')
+ cy.get('@resourcePageBtn').click()
+ cy.get(
+ 'gn-ui-form-field-online-resources gn-ui-online-resource-card'
+ ).should('have.length', 1)
+ })
+ it('modifies a resource', () => {
+ cy.get('gn-ui-form-field-online-resources gn-ui-online-resource-card')
+ .eq(0)
+ .as('wmsService')
+ cy.get('@wmsService')
+ .find('[data-test=card-title]')
+ .invoke('text')
+ .invoke('trim')
+ .should('eql', 'A layer name as identifier in service')
+ cy.editor_wrapPreviousDraft()
+ // open modify dialog
+ cy.get('@wmsService').find('button[data-test=card-modify]').click()
+ cy.get('gn-ui-modal-dialog')
+ .find('[data-cy="identifier-in-service"]')
+ .type('{selectall}{del}new identifier')
+ cy.get('gn-ui-modal-dialog [data-cy=confirm-button]').click()
+ cy.editor_publishAndReload()
+ cy.get('@resourcePageBtn').click()
+ cy.get('@wmsService')
+ .find('[data-test=card-title]')
+ .invoke('text')
+ .invoke('trim')
+ .should('eql', 'new identifier')
+ cy.get('@wmsService').scrollIntoView()
+ cy.screenshot({ capture: 'viewport' })
+ })
+ it('deletes a resource', () => {
+ // item count before deleting
+ cy.get(
+ 'gn-ui-form-field-online-resources gn-ui-online-resource-card'
+ ).should('have.length', 1)
+ cy.editor_wrapPreviousDraft()
+ // delete the first item
+ cy.get(
+ 'gn-ui-form-field-online-resources gn-ui-sortable-list [data-test=remove-item]'
+ )
+ .eq(0)
+ .click()
+ cy.editor_publishAndReload()
+ cy.get('@saveStatus').should('eq', 'record_up_to_date')
+ cy.get('@resourcePageBtn').click()
+ cy.get(
+ 'gn-ui-form-field-online-resources gn-ui-online-resource-card'
+ ).should('have.length', 0)
+ })
+ })
describe('attached resources', () => {
beforeEach(() => {
cy.get('@resourcePageBtn').click()
diff --git a/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.css b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html
new file mode 100644
index 0000000000..4ee656c480
--- /dev/null
+++ b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html
@@ -0,0 +1,31 @@
+
+
+ editor.record.form.field.onlineResource.edit.protocol
+
+
+ help
+
+
+
+
+
+ {{ protocolOption.label | translate }}
+
+
+
+
diff --git a/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.spec.ts b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.spec.ts
new file mode 100644
index 0000000000..d158c7e40a
--- /dev/null
+++ b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.spec.ts
@@ -0,0 +1,21 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing'
+import { TranslateModule } from '@ngx-translate/core'
+import { OnlineServiceResourceInputComponent } from './online-service-resource-input.component'
+
+describe('OnlineServiceResourceInputComponent', () => {
+ let component: OnlineServiceResourceInputComponent
+ let fixture: ComponentFixture
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [OnlineServiceResourceInputComponent, TranslateModule.forRoot()],
+ }).compileComponents()
+
+ fixture = TestBed.createComponent(OnlineServiceResourceInputComponent)
+ component = fixture.componentInstance
+ })
+
+ it('should create', () => {
+ expect(component).toBeTruthy()
+ })
+})
diff --git a/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts
new file mode 100644
index 0000000000..a7eab8ec5b
--- /dev/null
+++ b/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts
@@ -0,0 +1,82 @@
+import { CommonModule } from '@angular/common'
+import {
+ ChangeDetectionStrategy,
+ Component,
+ Input,
+ OnChanges,
+} from '@angular/core'
+import { FormsModule } from '@angular/forms'
+import { MatIconModule } from '@angular/material/icon'
+import { MatRadioModule } from '@angular/material/radio'
+import { MatTooltipModule } from '@angular/material/tooltip'
+import { marker } from '@biesbjerg/ngx-translate-extract-marker'
+import {
+ DatasetServiceDistribution,
+ ServiceProtocol,
+} from '@geonetwork-ui/common/domain/model/record'
+import { TextInputComponent } from '@geonetwork-ui/ui/inputs'
+import { TranslateModule } from '@ngx-translate/core'
+
+@Component({
+ selector: 'gn-ui-online-service-resource-input',
+ templateUrl: './online-service-resource-input.component.html',
+ styleUrls: ['./online-service-resource-input.component.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ standalone: true,
+ imports: [
+ CommonModule,
+ MatIconModule,
+ MatTooltipModule,
+ MatRadioModule,
+ FormsModule,
+ TextInputComponent,
+ TranslateModule,
+ ],
+})
+export class OnlineServiceResourceInputComponent implements OnChanges {
+ @Input() service: Omit
+ @Input() protocolHint?: string
+
+ selectedProtocol: ServiceProtocol
+
+ protocolOptions: {
+ label: string
+ value: ServiceProtocol
+ }[] = [
+ {
+ label: 'OGC API',
+ value: 'ogcFeatures',
+ },
+ {
+ label: 'WFS',
+ value: 'wfs',
+ },
+ {
+ label: 'WMS',
+ value: 'wms',
+ },
+ {
+ label: 'WMTS',
+ value: 'wmts',
+ },
+ {
+ label: 'WPS',
+ value: 'wps',
+ },
+ {
+ label: 'ESRI REST',
+ value: 'esriRest',
+ },
+ {
+ label: marker('editor.record.onlineResource.protocol.other'),
+ value: 'other',
+ },
+ ]
+
+ ngOnChanges() {
+ this.selectedProtocol =
+ this.protocolOptions.find(
+ (option) => option.value === this.service.accessServiceProtocol
+ )?.value ?? 'other'
+ }
+}
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html
index d8df0ccf3c..6bd1486741 100644
--- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html
+++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.html
@@ -20,15 +20,24 @@
-
- editor.record.form.field.onlineResource.edit.title
-
-
-
- editor.record.form.field.onlineResource.edit.description
-
-
+
+
+
+ editor.record.form.field.onlineResource.edit.title
+
+
+
+
+
+ editor.record.form.field.onlineResource.edit.description
+
+
+
+
+
+
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.ts
index a64b4aca96..a274dbc852 100644
--- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.ts
+++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-link-resources/form-field-online-link-resources.component.ts
@@ -16,6 +16,7 @@ import {
FileInputComponent,
TextAreaComponent,
TextInputComponent,
+ UrlInputComponent,
} from '@geonetwork-ui/ui/inputs'
import { CommonModule } from '@angular/common'
import { OnlineResourceCardComponent } from '../../../online-resource-card/online-resource-card.component'
@@ -43,6 +44,7 @@ import { MAX_UPLOAD_SIZE_MB } from '../../../../fields.config'
OnlineResourceCardComponent,
TextInputComponent,
TextAreaComponent,
+ UrlInputComponent,
TranslateModule,
],
})
@@ -154,6 +156,7 @@ export class FormFieldOnlineLinkResourcesComponent {
}
this.dialog
.open(ModalDialogComponent, {
+ width: '800px',
data: {
title: this.translateService.instant(
'editor.record.form.field.onlineResource.dialogTitle'
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.css b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.html
new file mode 100644
index 0000000000..8f40a8fc0f
--- /dev/null
+++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ editor.record.form.field.onlineResource.edit.title
+
+
+
+
+
+ editor.record.form.field.onlineResource.edit.description
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.spec.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.spec.ts
new file mode 100644
index 0000000000..307a0d5a62
--- /dev/null
+++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.spec.ts
@@ -0,0 +1,55 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing'
+import { TranslateModule } from '@ngx-translate/core'
+import { FormFieldOnlineResourcesComponent } from './form-field-online-resources.component'
+import { MockBuilder, MockProvider } from 'ng-mocks'
+import { Subject } from 'rxjs'
+import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
+import { NotificationsService } from '@geonetwork-ui/feature/notifications'
+import { MatDialog, MatDialogRef } from '@angular/material/dialog'
+
+let uploadSubject: Subject
+class PlatformServiceInterfaceMock {
+ attachFileToRecord = jest.fn(() => {
+ uploadSubject = new Subject()
+ return uploadSubject
+ })
+}
+export class MatDialogMock {
+ _subject = new Subject()
+ _closeWithValue = (v) => this._subject.next(v)
+ open = jest.fn(() => ({
+ afterClosed: () => this._subject,
+ }))
+}
+
+describe('FormFieldOnlineResourcesComponent', () => {
+ let component: FormFieldOnlineResourcesComponent
+ let fixture: ComponentFixture
+
+ beforeEach(() => {
+ return MockBuilder(FormFieldOnlineResourcesComponent)
+ })
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ imports: [TranslateModule.forRoot()],
+ providers: [
+ MockProvider(
+ PlatformServiceInterface,
+ PlatformServiceInterfaceMock,
+ 'useClass'
+ ),
+ MockProvider(NotificationsService),
+ MockProvider(MatDialogRef),
+ MockProvider(MatDialog, MatDialogMock, 'useClass'),
+ ],
+ }).compileComponents()
+
+ fixture = TestBed.createComponent(FormFieldOnlineResourcesComponent)
+ component = fixture.componentInstance
+ })
+
+ it('should create', () => {
+ expect(component).toBeTruthy()
+ })
+})
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts
new file mode 100644
index 0000000000..afec5556fb
--- /dev/null
+++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts
@@ -0,0 +1,241 @@
+import { CommonModule } from '@angular/common'
+import {
+ ChangeDetectionStrategy,
+ ChangeDetectorRef,
+ Component,
+ EventEmitter,
+ Input,
+ Output,
+ TemplateRef,
+ ViewChild,
+} from '@angular/core'
+import { MatDialog } from '@angular/material/dialog'
+import { marker } from '@biesbjerg/ngx-translate-extract-marker'
+import {
+ DatasetDownloadDistribution,
+ DatasetServiceDistribution,
+ OnlineResource,
+ ServiceEndpoint,
+} from '@geonetwork-ui/common/domain/model/record'
+import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
+import { NotificationsService } from '@geonetwork-ui/feature/notifications'
+import {
+ FileInputComponent,
+ SwitchToggleComponent,
+ SwitchToggleOption,
+ TextAreaComponent,
+ TextInputComponent,
+ UrlInputComponent,
+} from '@geonetwork-ui/ui/inputs'
+import {
+ ModalDialogComponent,
+ SortableListComponent,
+} from '@geonetwork-ui/ui/layout'
+import { TranslateModule, TranslateService } from '@ngx-translate/core'
+import { Subscription } from 'rxjs'
+import { MAX_UPLOAD_SIZE_MB } from '../../../../fields.config'
+import { OnlineResourceCardComponent } from '../../../online-resource-card/online-resource-card.component'
+import { OnlineServiceResourceInputComponent } from '../../../online-service-resource-input/online-service-resource-input.component'
+
+type OnlineNotLinkResource =
+ | DatasetDownloadDistribution
+ | DatasetServiceDistribution
+ | ServiceEndpoint
+
+@Component({
+ selector: 'gn-ui-form-field-online-resources',
+ templateUrl: './form-field-online-resources.component.html',
+ styleUrls: ['./form-field-online-resources.component.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ standalone: true,
+ imports: [
+ CommonModule,
+ SwitchToggleComponent,
+ FileInputComponent,
+ OnlineServiceResourceInputComponent,
+ UrlInputComponent,
+ SortableListComponent,
+ OnlineResourceCardComponent,
+ TextInputComponent,
+ TextAreaComponent,
+ TranslateModule,
+ ],
+})
+export class FormFieldOnlineResourcesComponent {
+ @Input() metadataUuid: string
+ @Input() set value(onlineResources: Array) {
+ this.allResources = onlineResources
+ this.notLinkResources = onlineResources.filter(
+ (res): res is OnlineNotLinkResource => res.type !== 'link'
+ )
+ }
+ @Output() valueChange: EventEmitter> =
+ new EventEmitter()
+
+ @ViewChild('dialogTemplate') dialogTemplate: TemplateRef
+
+ typeOptions: SwitchToggleOption[] = [
+ {
+ label: marker('editor.record.form.field.onlineResource.toggle.dataset'),
+ value: 'download',
+ checked: true,
+ },
+ {
+ label: marker('editor.record.form.field.onlineResource.toggle.service'),
+ value: 'service',
+ checked: false,
+ },
+ ]
+ selectedType: 'download' | 'service' = 'download'
+
+ private allResources: OnlineResource[] = []
+ notLinkResources: OnlineNotLinkResource[] = []
+ uploadProgress = undefined
+ uploadSubscription: Subscription = null
+ newService = {
+ type: 'service',
+ accessServiceProtocol: 'ogcFeatures',
+ identifierInService: '',
+ } as Omit
+
+ protected MAX_UPLOAD_SIZE_MB = MAX_UPLOAD_SIZE_MB
+
+ constructor(
+ private notificationsService: NotificationsService,
+ private translateService: TranslateService,
+ private platformService: PlatformServiceInterface,
+ private cd: ChangeDetectorRef,
+ private dialog: MatDialog
+ ) {}
+
+ onSelectedTypeChange(selectedType: unknown) {
+ this.selectedType = selectedType as 'download' | 'service'
+ }
+
+ handleFileChange(file: File) {
+ this.uploadProgress = 0
+ this.uploadSubscription = this.platformService
+ .attachFileToRecord(this.metadataUuid, file)
+ .subscribe({
+ next: (event) => {
+ if (event.type === 'progress') {
+ this.uploadProgress = event.progress
+ this.cd.detectChanges()
+ } else if (event.type === 'success') {
+ this.uploadProgress = undefined
+ this.cd.detectChanges()
+ const newResource: DatasetDownloadDistribution = {
+ type: 'download',
+ url: new URL(event.attachment.url),
+ name: event.attachment.fileName,
+ sizeBytes: event.sizeBytes, // WARNING: this is the only time that sizeBytes is set
+ }
+ this.valueChange.emit([...this.allResources, newResource])
+ }
+ },
+ error: (error: Error) => this.handleError(error.message),
+ })
+ }
+
+ handleUploadCancel() {
+ if (this.uploadSubscription) {
+ this.uploadProgress = undefined
+ this.uploadSubscription.unsubscribe()
+ }
+ }
+
+ handleDownloadUrlChange(url: string) {
+ try {
+ const name = url.split('/').pop()
+ const newLink: DatasetDownloadDistribution = {
+ type: 'download',
+ url: new URL(url),
+ name,
+ }
+ this.valueChange.emit([...this.allResources, newLink])
+ } catch (e) {
+ this.handleError((e as Error).message)
+ }
+ }
+
+ handleServiceUrlChange(url: string) {
+ this.valueChange.emit([
+ ...this.allResources,
+ {
+ ...this.newService,
+ url: new URL(url),
+ },
+ ])
+ }
+
+ handleServiceModify(
+ oldService: DatasetServiceDistribution,
+ newService: DatasetServiceDistribution
+ ) {
+ oldService.accessServiceProtocol = newService.accessServiceProtocol
+ oldService.identifierInService = newService.identifierInService
+ oldService.url = newService.url
+ }
+
+ handleResourcesChange(items: unknown[]) {
+ const notLinks = items as OnlineNotLinkResource[]
+ const newResources = [
+ ...this.allResources.filter((r) => r.type === 'link'),
+ ...notLinks,
+ ]
+ this.valueChange.emit(newResources)
+ }
+
+ handleResourceModify(resource: OnlineNotLinkResource, index: number) {
+ this.openEditDialog(resource, index)
+ }
+
+ private handleError(error: string) {
+ this.uploadProgress = undefined
+ this.notificationsService.showNotification({
+ type: 'error',
+ title: this.translateService.instant(
+ 'editor.record.onlineResourceError.title'
+ ),
+ text: `${this.translateService.instant(
+ 'editor.record.onlineResourceError.body'
+ )} ${error}`,
+ closeMessage: this.translateService.instant(
+ 'editor.record.onlineResourceError.closeMessage'
+ ),
+ })
+ }
+
+ private openEditDialog(resource: OnlineNotLinkResource, index: number) {
+ const resourceCopy = {
+ ...resource,
+ }
+ this.dialog
+ .open(ModalDialogComponent, {
+ width: '800px',
+ data: {
+ title: this.translateService.instant(
+ 'editor.record.form.field.onlineResource.dialogTitle'
+ ),
+ body: this.dialogTemplate,
+ bodyContext: resourceCopy,
+ confirmText: this.translateService.instant(
+ 'editor.record.form.field.onlineResource.confirm'
+ ),
+ cancelText: this.translateService.instant(
+ 'editor.record.form.field.onlineResource.cancel'
+ ),
+ },
+ })
+ .afterClosed()
+ .subscribe((confirmed: boolean) => {
+ if (!confirmed) return
+ const newNotLinks = [...this.notLinkResources]
+ newNotLinks.splice(index, 1, resourceCopy)
+ this.valueChange.emit([
+ ...this.allResources.filter((r) => r.type === 'link'),
+ ...newNotLinks,
+ ])
+ })
+ }
+}
diff --git a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html
index d48c8df844..8c6854f243 100644
--- a/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html
+++ b/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html
@@ -120,6 +120,13 @@
(valueChange)="valueChange.emit($event)"
>
+
+
+
+
+
-
-
diff --git a/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.html b/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.html
index 601c3b0df7..5a144886eb 100644
--- a/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.html
+++ b/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.html
@@ -9,6 +9,6 @@
[checked]="option.checked"
(change)="onChange(option)"
[class]="extraClasses"
- >{{ option.label }}{{ option.label | translate }}
diff --git a/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.ts b/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.ts
index 72d8f9e161..4a0df6ba02 100644
--- a/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.ts
+++ b/libs/ui/inputs/src/lib/switch-toggle/switch-toggle.component.ts
@@ -7,9 +7,11 @@ import {
Output,
} from '@angular/core'
import { MatButtonToggleModule } from '@angular/material/button-toggle'
+import { TranslateModule } from '@ngx-translate/core'
export type SwitchToggleOption = {
label: string
+ value?: unknown
checked: boolean
}
@@ -19,7 +21,7 @@ export type SwitchToggleOption = {
styleUrls: ['./switch-toggle.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
- imports: [MatButtonToggleModule, CommonModule],
+ imports: [MatButtonToggleModule, CommonModule, TranslateModule],
})
export class SwitchToggleComponent {
@Input() options: SwitchToggleOption[]
diff --git a/libs/ui/inputs/src/lib/url-input/url-input.component.html b/libs/ui/inputs/src/lib/url-input/url-input.component.html
index 2f964788dc..9944a4b428 100644
--- a/libs/ui/inputs/src/lib/url-input/url-input.component.html
+++ b/libs/ui/inputs/src/lib/url-input/url-input.component.html
@@ -27,7 +27,11 @@
diff --git a/libs/ui/inputs/src/lib/url-input/url-input.component.spec.ts b/libs/ui/inputs/src/lib/url-input/url-input.component.spec.ts
index d90106b83c..ba96445896 100644
--- a/libs/ui/inputs/src/lib/url-input/url-input.component.spec.ts
+++ b/libs/ui/inputs/src/lib/url-input/url-input.component.spec.ts
@@ -78,15 +78,27 @@ describe('UrlInputComponent', () => {
})
describe('button', () => {
- it('is disabled if value is input empty', () => {
+ it('is disabled if parent set it as disabled', () => {
+ component.disabled = true
inputEl.value = ''
fixture.detectChanges()
expect(button.componentInstance.disabled).toBe(true)
})
+ it('is disabled if value is empty', () => {
+ inputEl.value = ''
+ fixture.detectChanges()
+ expect(button.componentInstance.disabled).toBe(true)
+ })
+ it('is disabled if asking for parseable URL and value is not an URL', () => {
+ component.urlCanParse = true
+ inputEl.value = 'hello'
+ fixture.detectChanges()
+ expect(button.componentInstance.disabled).toBe(true)
+ })
it('is not disabled otherwise', () => {
inputEl.value = 'hello'
fixture.detectChanges()
- expect(button.componentInstance.disabled).toBe(false)
+ expect(button.componentInstance.disabled).toBeFalsy()
})
})
})
diff --git a/libs/ui/inputs/src/lib/url-input/url-input.component.ts b/libs/ui/inputs/src/lib/url-input/url-input.component.ts
index 2cca056e24..9bafd36ad0 100644
--- a/libs/ui/inputs/src/lib/url-input/url-input.component.ts
+++ b/libs/ui/inputs/src/lib/url-input/url-input.component.ts
@@ -1,4 +1,11 @@
-import { ChangeDetectorRef, Component, Input, Output } from '@angular/core'
+import {
+ ChangeDetectorRef,
+ Component,
+ Input,
+ OnChanges,
+ Output,
+ SimpleChanges,
+} from '@angular/core'
import { CommonModule } from '@angular/common'
import { ButtonComponent } from '../button/button.component'
import { MatIconModule } from '@angular/material/icon'
@@ -12,16 +19,23 @@ import { Subject } from 'rxjs'
standalone: true,
imports: [CommonModule, ButtonComponent, MatIconModule],
})
-export class UrlInputComponent {
+export class UrlInputComponent implements OnChanges {
@Input() value = ''
@Input() extraClass = ''
@Input() placeholder = 'https://'
@Input() disabled: boolean
+ @Input() urlCanParse?: boolean
rawChange = new Subject()
@Output() valueChange = this.rawChange.pipe(filter((v) => !!v))
constructor(private cd: ChangeDetectorRef) {}
+ ngOnChanges(changes: SimpleChanges): void {
+ if (changes.value) {
+ console.log('changes.value', changes.value)
+ }
+ }
+
handleInput() {
this.cd.markForCheck()
}
@@ -30,4 +44,13 @@ export class UrlInputComponent {
const value = element.value
this.rawChange.next(value)
}
+
+ URLcanParse(url: string): boolean {
+ try {
+ new URL(url)
+ return true
+ } catch (e) {
+ return false
+ }
+ }
}
diff --git a/translations/de.json b/translations/de.json
index 38b8ea9523..c1b87f22af 100644
--- a/translations/de.json
+++ b/translations/de.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "",
"catalog.figures.datasets": "{count, plural, =0{Datensätze} one{Datensatz} other{Datensätze}}",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "",
"editor.record.form.field.onlineResource.dialogTitle": "",
"editor.record.form.field.onlineResource.edit.description": "",
+ "editor.record.form.field.onlineResource.edit.protocol": "",
"editor.record.form.field.onlineResource.edit.title": "",
"editor.record.form.field.onlineResource.fileSize": "",
"editor.record.form.field.onlineResource.modify": "",
+ "editor.record.form.field.onlineResource.toggle.dataset": "",
+ "editor.record.form.field.onlineResource.toggle.service": "",
+ "editor.record.form.field.onlineResources": "",
"editor.record.form.field.overviews": "",
"editor.record.form.field.recordUpdated": "Datensatz zuletzt aktualisiert",
"editor.record.form.field.resourceUpdated": "Letztes Aktualisierungsdatum",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "",
"editor.record.form.section.about.description": "",
"editor.record.form.section.about.label": "",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "",
"editor.record.form.section.associatedResources.description": "",
"editor.record.form.section.associatedResources.label": "",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "Der Datensatz konnte nicht geladen werden:",
"editor.record.loadError.closeMessage": "Verstanden",
"editor.record.loadError.title": "Fehler beim Laden des Datensatzes",
+ "editor.record.onlineResource.protocol.other": "",
"editor.record.onlineResourceError.body": "",
"editor.record.onlineResourceError.closeMessage": "",
"editor.record.onlineResourceError.title": "",
diff --git a/translations/en.json b/translations/en.json
index 3ec0245834..caa19df1ca 100644
--- a/translations/en.json
+++ b/translations/en.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "Log in",
"catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "Confirm",
"editor.record.form.field.onlineResource.dialogTitle": "Modify the resource preview",
"editor.record.form.field.onlineResource.edit.description": "Description",
+ "editor.record.form.field.onlineResource.edit.protocol": "Protocol",
"editor.record.form.field.onlineResource.edit.title": "Title",
"editor.record.form.field.onlineResource.fileSize": "{sizeMB}MB",
"editor.record.form.field.onlineResource.modify": "Modify",
+ "editor.record.form.field.onlineResource.toggle.dataset": "Link to a dataset",
+ "editor.record.form.field.onlineResource.toggle.service": "Link to a service",
+ "editor.record.form.field.onlineResources": "Distribution",
"editor.record.form.field.overviews": "Overviews",
"editor.record.form.field.recordUpdated": "Record Updated",
"editor.record.form.field.resourceUpdated": "Resource Updated",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "Resources",
"editor.record.form.section.about.description": "This section describes the resource.",
"editor.record.form.section.about.label": "About the resource",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "Annexes",
"editor.record.form.section.associatedResources.description": "Drop files here to associate them with the resource.",
"editor.record.form.section.associatedResources.label": "Associated resources",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "The record could not be loaded:",
"editor.record.loadError.closeMessage": "Understood",
"editor.record.loadError.title": "Error loading record",
+ "editor.record.onlineResource.protocol.other": "Other",
"editor.record.onlineResourceError.body": "An error occurred while adding the resource:",
"editor.record.onlineResourceError.closeMessage": "Understood",
"editor.record.onlineResourceError.title": "Error adding resource",
diff --git a/translations/es.json b/translations/es.json
index 6f87aa7c9d..efda33c0a8 100644
--- a/translations/es.json
+++ b/translations/es.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "",
"catalog.figures.datasets": "conjuntos de datos",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "",
"editor.record.form.field.onlineResource.dialogTitle": "",
"editor.record.form.field.onlineResource.edit.description": "",
+ "editor.record.form.field.onlineResource.edit.protocol": "",
"editor.record.form.field.onlineResource.edit.title": "",
"editor.record.form.field.onlineResource.fileSize": "",
"editor.record.form.field.onlineResource.modify": "",
+ "editor.record.form.field.onlineResource.toggle.dataset": "",
+ "editor.record.form.field.onlineResource.toggle.service": "",
+ "editor.record.form.field.onlineResources": "",
"editor.record.form.field.overviews": "",
"editor.record.form.field.recordUpdated": "",
"editor.record.form.field.resourceUpdated": "",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "",
"editor.record.form.section.about.description": "",
"editor.record.form.section.about.label": "",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "",
"editor.record.form.section.associatedResources.description": "",
"editor.record.form.section.associatedResources.label": "",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "",
"editor.record.loadError.closeMessage": "",
"editor.record.loadError.title": "",
+ "editor.record.onlineResource.protocol.other": "",
"editor.record.onlineResourceError.body": "",
"editor.record.onlineResourceError.closeMessage": "",
"editor.record.onlineResourceError.title": "",
diff --git a/translations/fr.json b/translations/fr.json
index 9cd20a7b16..ec137b47af 100644
--- a/translations/fr.json
+++ b/translations/fr.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "Se connecter",
"catalog.figures.datasets": "{count, plural, =0{données} one{donnée} other{données}}",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "Valider",
"editor.record.form.field.onlineResource.dialogTitle": "Modifier l'aperçu de la ressource",
"editor.record.form.field.onlineResource.edit.description": "Description",
+ "editor.record.form.field.onlineResource.edit.protocol": "Protocole",
"editor.record.form.field.onlineResource.edit.title": "Titre",
"editor.record.form.field.onlineResource.fileSize": "{sizeMB} Mo",
"editor.record.form.field.onlineResource.modify": "Modifier",
+ "editor.record.form.field.onlineResource.toggle.dataset": "Lier un jeu de données",
+ "editor.record.form.field.onlineResource.toggle.service": "Lier un service",
+ "editor.record.form.field.onlineResources": "Distribution",
"editor.record.form.field.overviews": "Aperçus",
"editor.record.form.field.recordUpdated": "Date de dernière révision",
"editor.record.form.field.resourceUpdated": "Date de dernière révision",
@@ -240,8 +245,9 @@
"editor.record.form.page.ressources": "Ressources",
"editor.record.form.section.about.description": "Ces informations concernent la donnée.",
"editor.record.form.section.about.label": "À propos de la ressource",
+ "editor.record.form.section.annexes.description": "Les annexes sont optionnels. Ce sont des pièces jointes de la fiche de métadonnées qui peuvent aider à mieux comprendre la donnée (notice, etc.)",
"editor.record.form.section.annexes.label": "Annexes",
- "editor.record.form.section.associatedResources.description": "Déposez les jeux de données associées à cette fiche de métadonnées.",
+ "editor.record.form.section.associatedResources.description": "Liez des jeux de données ou des services associés à cette fiche de métadonnée.",
"editor.record.form.section.associatedResources.label": "Ressources associées",
"editor.record.form.section.classification.description": "La classification a un impact sur la recherche du jeu de données.",
"editor.record.form.section.classification.label": "Classification",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "La fiche n'a pas pu être chargée :",
"editor.record.loadError.closeMessage": "Compris",
"editor.record.loadError.title": "Erreur lors du chargement",
+ "editor.record.onlineResource.protocol.other": "Autre",
"editor.record.onlineResourceError.body": "Une erreur est survenue lors de l'ajout de la ressource :",
"editor.record.onlineResourceError.closeMessage": "Compris",
"editor.record.onlineResourceError.title": "Erreur lors de l'ajout d'une ressource",
diff --git a/translations/it.json b/translations/it.json
index 6508983d02..bd3a0b1fe5 100644
--- a/translations/it.json
+++ b/translations/it.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "",
"catalog.figures.datasets": "{count, plural, =0{datasets} one{dataset} other{datasets}}",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "",
"editor.record.form.field.onlineResource.dialogTitle": "",
"editor.record.form.field.onlineResource.edit.description": "",
+ "editor.record.form.field.onlineResource.edit.protocol": "",
"editor.record.form.field.onlineResource.edit.title": "",
"editor.record.form.field.onlineResource.fileSize": "",
"editor.record.form.field.onlineResource.modify": "",
+ "editor.record.form.field.onlineResource.toggle.dataset": "",
+ "editor.record.form.field.onlineResource.toggle.service": "",
+ "editor.record.form.field.onlineResources": "",
"editor.record.form.field.overviews": "",
"editor.record.form.field.recordUpdated": "",
"editor.record.form.field.resourceUpdated": "",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "",
"editor.record.form.section.about.description": "",
"editor.record.form.section.about.label": "",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "",
"editor.record.form.section.associatedResources.description": "",
"editor.record.form.section.associatedResources.label": "",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "",
"editor.record.loadError.closeMessage": "",
"editor.record.loadError.title": "",
+ "editor.record.onlineResource.protocol.other": "",
"editor.record.onlineResourceError.body": "",
"editor.record.onlineResourceError.closeMessage": "",
"editor.record.onlineResourceError.title": "",
diff --git a/translations/nl.json b/translations/nl.json
index d6ab9c4d22..d072235754 100644
--- a/translations/nl.json
+++ b/translations/nl.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "",
"catalog.figures.datasets": "datasets",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "",
"editor.record.form.field.onlineResource.dialogTitle": "",
"editor.record.form.field.onlineResource.edit.description": "",
+ "editor.record.form.field.onlineResource.edit.protocol": "",
"editor.record.form.field.onlineResource.edit.title": "",
"editor.record.form.field.onlineResource.fileSize": "",
"editor.record.form.field.onlineResource.modify": "",
+ "editor.record.form.field.onlineResource.toggle.dataset": "",
+ "editor.record.form.field.onlineResource.toggle.service": "",
+ "editor.record.form.field.onlineResources": "",
"editor.record.form.field.overviews": "",
"editor.record.form.field.recordUpdated": "",
"editor.record.form.field.resourceUpdated": "",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "",
"editor.record.form.section.about.description": "",
"editor.record.form.section.about.label": "",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "",
"editor.record.form.section.associatedResources.description": "",
"editor.record.form.section.associatedResources.label": "",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "",
"editor.record.loadError.closeMessage": "",
"editor.record.loadError.title": "",
+ "editor.record.onlineResource.protocol.other": "",
"editor.record.onlineResourceError.body": "",
"editor.record.onlineResourceError.closeMessage": "",
"editor.record.onlineResourceError.title": "",
diff --git a/translations/pt.json b/translations/pt.json
index 58f0dd7185..82c457f271 100644
--- a/translations/pt.json
+++ b/translations/pt.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "",
"catalog.figures.datasets": "conjuntos de dados",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "",
"editor.record.form.field.onlineResource.dialogTitle": "",
"editor.record.form.field.onlineResource.edit.description": "",
+ "editor.record.form.field.onlineResource.edit.protocol": "",
"editor.record.form.field.onlineResource.edit.title": "",
"editor.record.form.field.onlineResource.fileSize": "",
"editor.record.form.field.onlineResource.modify": "",
+ "editor.record.form.field.onlineResource.toggle.dataset": "",
+ "editor.record.form.field.onlineResource.toggle.service": "",
+ "editor.record.form.field.onlineResources": "",
"editor.record.form.field.overviews": "",
"editor.record.form.field.recordUpdated": "",
"editor.record.form.field.resourceUpdated": "",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "",
"editor.record.form.section.about.description": "",
"editor.record.form.section.about.label": "",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "",
"editor.record.form.section.associatedResources.description": "",
"editor.record.form.section.associatedResources.label": "",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "",
"editor.record.loadError.closeMessage": "",
"editor.record.loadError.title": "",
+ "editor.record.onlineResource.protocol.other": "",
"editor.record.onlineResourceError.body": "",
"editor.record.onlineResourceError.closeMessage": "",
"editor.record.onlineResourceError.title": "",
diff --git a/translations/sk.json b/translations/sk.json
index c71d528ab3..d5e3632cc6 100644
--- a/translations/sk.json
+++ b/translations/sk.json
@@ -1,4 +1,5 @@
{
+ "": "",
"Add Layer As": "",
"button.login": "",
"catalog.figures.datasets": "{count, plural, =0{datasety} one{dataset} other{datasety}}",
@@ -215,9 +216,13 @@
"editor.record.form.field.onlineResource.confirm": "",
"editor.record.form.field.onlineResource.dialogTitle": "",
"editor.record.form.field.onlineResource.edit.description": "",
+ "editor.record.form.field.onlineResource.edit.protocol": "",
"editor.record.form.field.onlineResource.edit.title": "",
"editor.record.form.field.onlineResource.fileSize": "",
"editor.record.form.field.onlineResource.modify": "",
+ "editor.record.form.field.onlineResource.toggle.dataset": "",
+ "editor.record.form.field.onlineResource.toggle.service": "",
+ "editor.record.form.field.onlineResources": "",
"editor.record.form.field.overviews": "",
"editor.record.form.field.recordUpdated": "",
"editor.record.form.field.resourceUpdated": "",
@@ -240,6 +245,7 @@
"editor.record.form.page.ressources": "",
"editor.record.form.section.about.description": "",
"editor.record.form.section.about.label": "",
+ "editor.record.form.section.annexes.description": "",
"editor.record.form.section.annexes.label": "",
"editor.record.form.section.associatedResources.description": "",
"editor.record.form.section.associatedResources.label": "",
@@ -263,6 +269,7 @@
"editor.record.loadError.body": "",
"editor.record.loadError.closeMessage": "",
"editor.record.loadError.title": "",
+ "editor.record.onlineResource.protocol.other": "",
"editor.record.onlineResourceError.body": "",
"editor.record.onlineResourceError.closeMessage": "",
"editor.record.onlineResourceError.title": "",