Skip to content

Commit

Permalink
Merge pull request #1114 from geonetwork/service-layer-suggestion
Browse files Browse the repository at this point in the history
Editor: Service as resource layer suggestion
  • Loading branch information
AlitaBernachot authored Feb 11, 2025
2 parents a1ec7cf + c9f4177 commit 89bb09d
Show file tree
Hide file tree
Showing 16 changed files with 403 additions and 30 deletions.
12 changes: 6 additions & 6 deletions apps/metadata-editor-e2e/src/e2e/edit.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ describe('editor form', () => {
// 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')
.contains('WPS')
.click()
cy.get('gn-ui-form-field-online-resources')
.find('gn-ui-url-input')
Expand All @@ -519,15 +519,15 @@ describe('editor form', () => {
it('modifies a resource', () => {
cy.get('gn-ui-form-field-online-resources gn-ui-online-resource-card')
.eq(0)
.as('wmsService')
cy.get('@wmsService')
.as('resourceService')
cy.get('@resourceService')
.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('@resourceService').find('button[data-test=card-modify]').click()
cy.get(
'gn-ui-modal-dialog [data-cy="identifier-in-service"] input'
).clear()
Expand All @@ -537,12 +537,12 @@ describe('editor form', () => {
cy.get('gn-ui-modal-dialog [data-cy=confirm-button]').click()
cy.editor_publishAndReload()
cy.get('@resourcePageBtn').click()
cy.get('@wmsService')
cy.get('@resourceService')
.find('[data-test=card-title]')
.invoke('text')
.invoke('trim')
.should('eql', 'new identifier')
cy.get('@wmsService').scrollIntoView()
cy.get('@resourceService').scrollIntoView()
cy.screenshot({ capture: 'viewport' })
})
it('deletes a resource', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
class="flex flex-row gap-[8px]"
[(ngModel)]="service.accessServiceProtocol"
[disabled]="disabled"
(change)="resetLayersSuggestion()"
>
<mat-radio-button
*ngFor="let protocolOption of protocolOptions"
Expand All @@ -30,29 +31,59 @@ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
<div class="flex flex-col gap-4">
<gn-ui-url-input
class="w-full"
(valueChange)="handleUrlChange($event)"
(uploadClick)="handleUploadClick($event)"
(valueChange)="handleUrlValueChange($event)"
[disabled]="disabled"
[value]="url"
[showValidateButton]="false"
[showValidateButton]="activeLayerSuggestion"
>
<ng-icon name="iconoirCloudUpload"></ng-icon>
<ng-content *ngIf="activeLayerSuggestion">
<ng-icon name="iconoirCloudUpload"></ng-icon>
</ng-content>
</gn-ui-url-input>

<p class="text-sm text-red-500 pl-4" *ngIf="errorMessage" translate>
editor.record.form.field.onlineResource.edit.identifier.error
</p>

<gn-ui-text-input
class="grow border-b border-gray-300 pb-4"
[(value)]="service.identifierInService"
[placeholder]="getIdentifierPlaceholder() | translate"
data-cy="identifier-in-service"
[disabled]="disabled"
*ngIf="
!activeLayerSuggestion ||
(url && errorMessage) ||
(modifyMode && layers === undefined)
"
></gn-ui-text-input>

<gn-ui-dropdown-selector
class="border-b border-gray-300 pb-4"
[showTitle]="false"
[title]="
'editor.record.form.field.onlineResource.edit.identifier.select.label'
| translate
"
[choices]="layers || []"
*ngIf="activeLayerSuggestion && layers !== undefined"
[selected]="service.identifierInService"
(selectValue)="handleSelectValue($event)"
>
</gn-ui-dropdown-selector>
<gn-ui-button
(buttonClick)="submitIdentifier(service.identifierInService)"
[disabled]="disabled || !service.identifierInService || !url"
[disabled]="disabled || !service.identifierInService"
type="primary"
*ngIf="
!modifyMode &&
((activeLayerSuggestion && layers) ||
!activeLayerSuggestion ||
(url && errorMessage))
"
>
<span class="text-white font-bold" translate
>editor.record.form.field.onlineResource.edit.identifier.submit</span
<span class="text-white font-bold" translate>
editor.record.form.field.onlineResource.edit.identifier.submit</span
>
</gn-ui-button>
</div>
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { CommonModule } from '@angular/common'
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
EventEmitter,
Input,
OnChanges,
OnInit,
Output,
} from '@angular/core'
import { FormsModule } from '@angular/forms'
Expand All @@ -17,6 +19,8 @@ import {
} from '@geonetwork-ui/common/domain/model/record'
import {
ButtonComponent,
DropdownChoice,
DropdownSelectorComponent,
TextInputComponent,
UrlInputComponent,
} from '@geonetwork-ui/ui/inputs'
Expand All @@ -27,6 +31,7 @@ import {
provideNgIconsConfig,
} from '@ng-icons/core'
import { iconoirCloudUpload } from '@ng-icons/iconoir'
import { getLayers } from '@geonetwork-ui/util/shared'

@Component({
selector: 'gn-ui-online-service-resource-input',
Expand All @@ -35,6 +40,7 @@ import { iconoirCloudUpload } from '@ng-icons/iconoir'
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [
DropdownSelectorComponent,
ButtonComponent,
CommonModule,
FormsModule,
Expand All @@ -52,18 +58,21 @@ import { iconoirCloudUpload } from '@ng-icons/iconoir'
}),
],
})
export class OnlineServiceResourceInputComponent implements OnChanges {
@Input() service: Omit<DatasetServiceDistribution, 'url'>
export class OnlineServiceResourceInputComponent implements OnChanges, OnInit {
@Input() service: DatasetServiceDistribution
@Input() protocolHint?: string
@Input() disabled? = false
@Input() modifyMode? = false
@Output() urlChange: EventEmitter<string> = new EventEmitter()
@Output() identifierSubmit: EventEmitter<{
url: string
identifier: string
}> = new EventEmitter()

errorMessage = false
selectedProtocol: ServiceProtocol
url: string
layers: DropdownChoice[] | undefined = undefined

protocolOptions: {
label: string
Expand Down Expand Up @@ -99,15 +108,65 @@ export class OnlineServiceResourceInputComponent implements OnChanges {
},
]

constructor(private cdr: ChangeDetectorRef) {}

get activeLayerSuggestion() {
return !['wps', 'GPFDL', 'esriRest', 'other'].includes(
this.service.accessServiceProtocol
)
}

ngOnChanges() {
this.selectedProtocol =
this.protocolOptions.find(
(option) => option.value === this.service.accessServiceProtocol
)?.value ?? 'other'
}

handleUrlChange(url: string) {
ngOnInit() {
if (this.service.url) {
this.url = this.service.url.toString()
}
}

handleUrlValueChange(url: string) {
this.url = url
this.service.url = new URL(url)
this.resetLayersSuggestion()
this.urlChange.emit(this.url)
}

async handleUploadClick(url: string) {
this.url = url

try {
const layers = await getLayers(url, this.service.accessServiceProtocol)
this.layers = layers.map((l) => {
return {
label: l.title ? `${l.title} ${l.name ? `(${l.name})` : ''}` : l.name,
value: l.name || l.title,
}
})

if (this.layers.length === 0) {
throw new Error('No layers found')
}
} catch (e) {
this.errorMessage = true
this.layers = undefined
}

this.cdr.detectChanges()
}

handleSelectValue(val: string) {
this.service.identifierInService = val
}

resetLayersSuggestion() {
this.errorMessage = false
this.layers = undefined
this.service.identifierInService = null
}

submitIdentifier(identifier: string) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<gn-ui-online-service-resource-input
[service]="newService"
[disabled]="disabled$ | async"
(urlChange)="handleServiceUrlChange($event)"
(identifierSubmit)="handleIdentifierSubmit($event)"
></gn-ui-online-service-resource-input>
</div>
Expand Down Expand Up @@ -55,19 +54,22 @@ <h3 class="text-[16px] font-bold text-main mb-[12px]" translate>
[(value)]="onlineResource.description"
></gn-ui-text-area>
</div>
<ng-container *ngIf="onlineResource.type === 'service'">
<ng-container *ngIf="onlineResource.type === 'service'; else urlInput">
<span class="w-full border-b border-gray-300"></span>
<gn-ui-online-service-resource-input
[service]="onlineResource"
[modifyMode]="true"
></gn-ui-online-service-resource-input>
</ng-container>
<span class="w-full border-b border-gray-300"></span>
<gn-ui-url-input
class="w-full"
[disabled]="true"
[value]="onlineResource.url"
[showValidateButton]="false"
></gn-ui-url-input>
<ng-template #urlInput>
<span class="w-full border-b border-gray-300"></span>
<gn-ui-url-input
class="w-full"
[disabled]="true"
[value]="onlineResource.url"
[showValidateButton]="false"
></gn-ui-url-input>
</ng-template>
</div>
</ng-template>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,12 @@ export class FormFieldOnlineResourcesComponent {
notLinkResources: OnlineNotLinkResource[] = []
uploadProgress = undefined
uploadSubscription: Subscription = null
newService = {
newService = <DatasetServiceDistribution>{
type: 'service',
accessServiceProtocol: 'ogcFeatures',
identifierInService: '',
} as Omit<DatasetServiceDistribution, 'url'>
url: undefined,
}

protected MAX_UPLOAD_SIZE_MB = MAX_UPLOAD_SIZE_MB

Expand Down
46 changes: 44 additions & 2 deletions libs/ui/inputs/src/lib/url-input/url-input.component.stories.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
import { Meta, StoryObj } from '@storybook/angular'
import {
applicationConfig,
Meta,
moduleMetadata,
StoryObj,
} from '@storybook/angular'
import {
NgIconComponent,
provideIcons,
provideNgIconsConfig,
} from '@ng-icons/core'
import { matStar } from '@ng-icons/material-icons/baseline'
import { UrlInputComponent } from './url-input.component'

export default {
title: 'Inputs/UrlInputComponent',
component: UrlInputComponent,
decorators: [],
decorators: [
moduleMetadata({
imports: [NgIconComponent],
}),
applicationConfig({
providers: [
provideIcons({
matStar,
}),
provideNgIconsConfig({
size: '0.9em',
}),
],
}),
],
argTypes: {
valueChange: {
action: 'valueChange',
Expand Down Expand Up @@ -56,3 +81,20 @@ export const WithoutUploadButton: StoryObj<UrlInputComponent> = {
</gn-ui-url-input>`,
}),
}

export const WithCustomValidateButton: StoryObj<UrlInputComponent> = {
args: {
value: null,
disabled: false,
placeholder: 'https://mysite.org/file',
showValidateButton: true,
},
render: (args) => ({
props: args,
template: `
<gn-ui-url-input [value]='value' [disabled]='disabled' [placeholder]='placeholder' [showValidateButton]='showValidateButton'
(valueChange)='valueChange($event)' (uploadClick)='uploadClick($event)'>
<ng-icon name='matStar'></ng-icon>
</gn-ui-url-input>`,
}),
}
Loading

0 comments on commit 89bb09d

Please sign in to comment.