Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metadata Editor: constraints fields #1032

Merged
merged 11 commits into from
Nov 17, 2024
Next Next commit
feat(editor): add constraints fields
feat(ui-inputs): add possibility to hide the
upload arrow in the url input component

WIP

chore: Divide open data license and
available licenses,
feat: preselect license if already present in
the record, toggle based on presence in the record

chore: Visually contain constraints list

chore: simplify the form-field-open-data logic

WIP: split license and constraints into separate components, add constraints to fields.config

WIP: changing editor fields configuration to
allow for (helper) components, introduce new
editor action that will later help with show/hide
components,
first working version for constraints shortcuts
toggle and displaying existing list of constraints

feat(editor): handle constraints text and url
change in constraint-card

feat(editor): save, update and delete constraints
in the record, add attach-button for more
constraints

chore: Remove sticky title from each constraint
(withouWrapper)

feat(editor): add logic to constraints shortcuts,
handle all three different constraint types,
enable/disable buttons based on existing
constraints

chore: Remove console.log

chore: update translations

chore(style): add line above each constraint card

chore: remove unused ng-onchanges

chore: Add header for each constraint,
add translations

chore: add unit tests for form field constraints

feat(editor): add new action to EditorFacade which
can set the visibility of a field

chore: Make translations work

feat(converter): support urls on constraints in ISO schemas

feat(constraints): show/hide fuctionality

chore: Add icon to button "add constraint"

chore: Refactor, add TODO
Angi-Kinas authored and jahow committed Nov 14, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit dad817d4acb20fe98aca2b7b9190f6032f7ad42d
Original file line number Diff line number Diff line change
@@ -398,7 +398,7 @@ Cette section contient des *caractères internationaux* (ainsi que des "caractè
<gmd:MD_ClassificationCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ClassificationCode" codeListValue="restricted"/>
</gmd:classification>
<gmd:useLimitation>
<gco:CharacterString>Contains sensitive information related to national defense</gco:CharacterString>
<gmx:Anchor xlink:href="https://security.org/document.pdf">Contains sensitive information related to national defense</gmx:Anchor>
<gmd:PT_FreeText>
<gmd:textGroup>
<gmd:LocalisedCharacterString locale="#EN">Contains sensitive information related to national defense</gmd:LocalisedCharacterString>
Original file line number Diff line number Diff line change
@@ -514,7 +514,7 @@ Cette section contient des *caractères internationaux* (ainsi que des "caractè
codeListValue="restricted"/>
</mco:classification>
<mco:useLimitation>
<gco:CharacterString>Contains sensitive information related to national defense</gco:CharacterString>
<gcx:Anchor xlink:href="https://security.org/document.pdf">Contains sensitive information related to national defense</gcx:Anchor>
<lan:PT_FreeText>
<mdb:textGroup>
<mdb:LocalisedCharacterString locale="#EN">Contains sensitive information related to national defense</mdb:LocalisedCharacterString>
Original file line number Diff line number Diff line change
@@ -377,7 +377,7 @@ Cette section contient des *caractères internationaux* (ainsi que des "caractè
codeListValue="restricted"/>
</mco:classification>
<mco:useLimitation>
<gco:CharacterString>Contains sensitive information related to national defense</gco:CharacterString>
<gcx:Anchor xlink:href="https://security.org/document.pdf">Contains sensitive information related to national defense</gcx:Anchor>
<lan:PT_FreeText>
<mdb:textGroup>
<mdb:LocalisedCharacterString locale="#EN">Contains sensitive information related to national defense</mdb:LocalisedCharacterString>
Original file line number Diff line number Diff line change
@@ -316,7 +316,7 @@ Cette section contient des *caractères internationaux* (ainsi que des "caractè
<gmd:MD_ClassificationCode codeList="http://standards.iso.org/iso/19139/resources/gmxCodelists.xml#MD_ClassificationCode" codeListValue="restricted"/>
</gmd:classification>
<gmd:useLimitation>
<gco:CharacterString>Contains sensitive information related to national defense</gco:CharacterString>
<gmx:Anchor xlink:href="https://security.org/document.pdf">Contains sensitive information related to national defense</gmx:Anchor>
<gmd:PT_FreeText>
<gmd:textGroup>
<gmd:LocalisedCharacterString locale="#EN">Contains sensitive information related to national defense</gmd:LocalisedCharacterString>
Original file line number Diff line number Diff line change
@@ -211,6 +211,7 @@ As such, **it is not very interesting at all.**`,
securityConstraints: [
{
text: 'Contains sensitive information related to national defense',
url: new URL('https://security.org/document.pdf'),
translations: {
text: {
fr: 'Contient des informations sensibles liées à la défense nationale',
101 changes: 75 additions & 26 deletions libs/api/metadata-converter/src/lib/iso19139/write-parts.ts
Original file line number Diff line number Diff line change
@@ -53,20 +53,13 @@ import { writeGeometry } from './utils/geometry'
import { namePartsToFull } from './utils/individual-name'
import { LANG_2_TO_3_MAPPER } from '@geonetwork-ui/util/i18n/language-codes'

export function writeCharacterString(
text: string
): ChainableFunction<XmlElement, XmlElement> {
return tap(
pipe(findChildOrCreate('gco:CharacterString'), setTextContent(text))
)
}

export function writeLocalizedCharacterString(
function writeLocalizedElement(
writeFn: ChainableFunction<XmlElement, XmlElement>,
text: string,
translations: FieldTranslation,
defaultLanguage: LanguageCode
): ChainableFunction<XmlElement, XmlElement> {
if (!translations) return writeCharacterString(text)
if (!translations) return writeFn
function createLocalized(lang: LanguageCode, translation: string) {
return pipe(
createNestedElement('gmd:textGroup', 'gmd:LocalisedCharacterString'),
@@ -75,7 +68,7 @@ export function writeLocalizedCharacterString(
)
}
return pipe(
writeCharacterString(text),
writeFn,
removeChildrenByName('gmd:PT_FreeText'),
createChild('gmd:PT_FreeText'),
appendChildren(
@@ -87,6 +80,27 @@ export function writeLocalizedCharacterString(
)
}

export function writeCharacterString(
text: string
): ChainableFunction<XmlElement, XmlElement> {
return tap(
pipe(findChildOrCreate('gco:CharacterString'), setTextContent(text))
)
}

export function writeLocalizedCharacterString(
text: string,
translations: FieldTranslation,
defaultLanguage: LanguageCode
): ChainableFunction<XmlElement, XmlElement> {
return writeLocalizedElement(
writeCharacterString(text),
text,
translations,
defaultLanguage
)
}

export function writeLinkage(
url: URL
): ChainableFunction<XmlElement, XmlElement> {
@@ -111,6 +125,20 @@ export function writeAnchor(
)
}

export function writeLocalizedAnchor(
url: URL,
text: string,
translations: FieldTranslation,
defaultLanguage: LanguageCode
): ChainableFunction<XmlElement, XmlElement> {
return writeLocalizedElement(
writeAnchor(url, text),
text,
translations,
defaultLanguage
)
}

export function writeDateTime(
date: Date
): ChainableFunction<XmlElement, XmlElement> {
@@ -466,11 +494,18 @@ export function createConstraint(
),
pipe(
createElement('gmd:useLimitation'),
writeLocalizedCharacterString(
constraint.text,
constraint.translations?.text,
defaultLanguage
)
'url' in constraint
? writeLocalizedAnchor(
constraint.url,
constraint.text,
constraint.translations?.text,
defaultLanguage
)
: writeLocalizedCharacterString(
constraint.text,
constraint.translations?.text,
defaultLanguage
)
)
)
)
@@ -491,11 +526,18 @@ export function createConstraint(
),
pipe(
createElement('gmd:otherConstraints'),
writeLocalizedCharacterString(
constraint.text,
constraint.translations?.text,
defaultLanguage
)
'url' in constraint
? writeLocalizedAnchor(
constraint.url,
constraint.text,
constraint.translations?.text,
defaultLanguage
)
: writeLocalizedCharacterString(
constraint.text,
constraint.translations?.text,
defaultLanguage
)
)
)
)
@@ -507,11 +549,18 @@ export function createConstraint(
'gmd:MD_Constraints',
'gmd:useLimitation'
),
writeLocalizedCharacterString(
constraint.text,
constraint.translations?.text,
defaultLanguage
)
'url' in constraint
? writeLocalizedAnchor(
constraint.url,
constraint.text,
constraint.translations?.text,
defaultLanguage
)
: writeLocalizedCharacterString(
constraint.text,
constraint.translations?.text,
defaultLanguage
)
)
}

6 changes: 6 additions & 0 deletions libs/feature/editor/src/lib/+state/editor.actions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createAction, props } from '@ngrx/store'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { SaveRecordError } from './editor.models'
import { EditorFieldIdentification } from '../models'

export const openRecord = createAction(
'[Editor] Open record',
@@ -35,3 +36,8 @@ export const setCurrentPage = createAction(
'[Editor] Set current page',
props<{ page: number }>()
)

export const setFieldVisibility = createAction(
'[Editor] Set field visibility',
props<{ field: EditorFieldIdentification; visible: boolean }>()
)
5 changes: 5 additions & 0 deletions libs/feature/editor/src/lib/+state/editor.facade.ts
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import * as EditorSelectors from './editor.selectors'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { filter } from 'rxjs'
import { Actions, ofType } from '@ngrx/effects'
import { EditorFieldIdentification } from '../models'

@Injectable()
export class EditorFacade {
@@ -58,4 +59,8 @@ export class EditorFacade {
setCurrentPage(page: number) {
this.store.dispatch(EditorActions.setCurrentPage({ page }))
}

setFieldVisibility(field: EditorFieldIdentification, visible: boolean) {
this.store.dispatch(EditorActions.setFieldVisibility({ field, visible }))
}
}
21 changes: 21 additions & 0 deletions libs/feature/editor/src/lib/+state/editor.reducer.ts
Original file line number Diff line number Diff line change
@@ -83,6 +83,27 @@ const reducer = createReducer(
on(EditorActions.setCurrentPage, (state, { page }) => ({
...state,
currentPage: page,
})),
on(EditorActions.setFieldVisibility, (state, { field, visible }) => ({
...state,
editorConfig: {
...state.editorConfig,
pages: state.editorConfig.pages.map((page) => ({
...page,
sections: page.sections.map((section) => ({
...section,
fields: section.fields.map((f) => {
if (f.model === field.model) {
return {
...f,
hidden: !visible,
}
}
return f
}),
})),
})),
},
}))
)

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<div class="flex flex-col gap-1 border rounded-lg p-4">
<gn-ui-form-field-rich
[label]="label"
[hint]="hint"
[value]="constraintText"
(valueChange)="handleConstraintTextChange($event)"
></gn-ui-form-field-rich>

<div *ngIf="!showUrlInput" class="flex-none mt-2">
<gn-ui-button (buttonClick)="displayUrlInput()" type="gray">
<mat-icon class="material-symbols-outlined me-1 text-primary"
>link</mat-icon
>
<span translate="">{{ 'input.image.displayUrlInput' }}</span>
</gn-ui-button>
</div>
<gn-ui-url-input
*ngIf="showUrlInput"
class="mt-3.5"
[value]="constraintURL ?? ''"
(valueChange)="handleURLChange($event)"
[disabled]="false"
[showUploadButton]="false"
>
</gn-ui-url-input>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ConstraintCardComponent } from './constraint-card.component';

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

beforeEach(() => {
TestBed.configureTestingModule({
imports: [ConstraintCardComponent]
});
fixture = TestBed.createComponent(ConstraintCardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
Output,
} from '@angular/core'
import { CommonModule } from '@angular/common'
import { MarkdownEditorComponent } from '@geonetwork-ui/ui/elements'
import { FormFieldRichComponent } from '../record-form/form-field/form-field-rich/form-field-rich.component'
import { ButtonComponent, UrlInputComponent } from '@geonetwork-ui/ui/inputs'
import { MatIconModule } from '@angular/material/icon'
import { TranslateModule } from '@ngx-translate/core'

@Component({
selector: 'gn-ui-constraint-card',
standalone: true,
imports: [
CommonModule,
MarkdownEditorComponent,
FormFieldRichComponent,
UrlInputComponent,
ButtonComponent,
MatIconModule,
TranslateModule,
],
templateUrl: './constraint-card.component.html',
styleUrls: ['./constraint-card.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ConstraintCardComponent {
@Input() label: string
@Input() constraintText: string
@Input() constraintURL: string
hint = 'editor.record.form.constraint.markdown.placeholder' // TODO: get text and translate

showUrlInput = false
@Output() urlChange = new EventEmitter<URL>()
@Output() constraintTextChange = new EventEmitter<string>()

handleConstraintTextChange(text: string) {
this.constraintTextChange.emit(text)
}

handleURLChange(url: string) {
this.urlChange.emit(new URL(url))
}

displayUrlInput() {
this.showUrlInput = true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<div class="flex flex-col gap-1">
<gn-ui-check-toggle
[label]="'editor.record.form.constraint.not.applicable' | translate"
[value]="toggleApplicableConstraint"
(toggled)="onToggleChange('toggleApplicableConstraint')"
data-cy="openDataToggle"
>
</gn-ui-check-toggle>
<gn-ui-check-toggle
[label]="'editor.record.form.constraint.not.known' | translate"
[value]="toggleKnownConstraint"
(toggled)="onToggleChange('toggleKnownConstraint')"
data-cy="openDataToggle"
>
</gn-ui-check-toggle>
</div>

<div
*ngIf="
toggleApplicableConstraint === false && toggleKnownConstraint === false
"
class="flex flex-row flex-wrap gap-2"
>
<ng-container *ngFor="let constraint of constraintButtonChoices">
<gn-ui-button
type="gray"
(buttonClick)="addConstraintSectionToDisplay(constraint)"
[disabled]="isConstraintButtonDisabled$(constraint) | async"
>
<mat-icon class="material-symbols-outlined text-primary">add</mat-icon>
&nbsp;
<span translate="">{{
'editor.record.form.constraint.' + constraint
}}</span>
</gn-ui-button>
</ng-container>
</div>
Loading