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

Implement a DCAT-AP converter using RDF #932

Merged
merged 12 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,33 @@ jobs:
comment_tag: github-links
pr_number: ${{ github.event.issue.number }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

apps:
needs: checks
if: github.event_name != 'issue_comment'
name: Deploy Apps to GitHub Pages
runs-on: ubuntu-latest
env:
BRANCH_NAME: main

steps:
- name: Checkout
uses: actions/checkout@v2

- name: Use Node.js ${{ env.NODE_VERSION }}
uses: actions/setup-node@v3
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install
run: npm ci

- name: Build metadata-converter
run: npx nx build metadata-converter --prod

- name: Deploy to directory ${{ env.BRANCH_NAME }}
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
npx gh-pages --dist dist/apps/ --dest ${{env.BRANCH_NAME}} --remove "${{env.BRANCH_NAME}}/**" --no-history --repo "https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git"
27 changes: 22 additions & 5 deletions apps/metadata-converter/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div class="grid grid-cols-3 grid-rows-auto auto-rows-min h-full">
<header class="col-span-3 flex flex-row items-center">
<header class="col-span-3 flex flex-row items-start">
<div>
<h1 class="text-[50px] font-bold font-title my-6 mx-10">
Simple metadata editor<br />
<div class="whitespace-nowrap">Simple metadata editor</div>
<gn-ui-status
#status
class="font-main font-normal text-gray-900 text-[16px]"
Expand All @@ -11,20 +11,37 @@ <h1 class="text-[50px] font-bold font-title my-6 mx-10">
></gn-ui-status>
</h1>
</div>
<div class="grow p-3">
<div class="grow shrink-0 p-3 min-w-[50%]">
<input
type="file"
accept=".xml, application/xml"
accept=".xml, .rdf, application/xml, application/rdf+xml, .jsonld, application/ld+json, application/json, .ttl, text/turtle, .n3, text/n3, .nt, application/n-triples"
class="mb-3 border border-gray-500 rounded-sm w-full bg-white p-2"
(change)="onFileSelect($event)"
placeholder="Upload a record from your computer"
/>
<input
type="text"
class="border border-gray-500 rounded-sm w-full bg-white p-2"
class="mb-3 border border-gray-500 rounded-sm w-full bg-white p-2"
(change)="onFileUrlInput($event.target.value)"
placeholder="...or enter a URL pointing to a metadata record"
/>
<div class="w-full">
<label
*ngFor="let format of formats | keyvalue"
class="mr-4"
[ngClass]="{ 'font-bold': format.key === originalFormat }"
>
<input
type="radio"
name="format"
[checked]="format.key === currentFormat"
[value]="format.key"
(change)="onFormatChange($event.target.value)"
/>
{{ format.key }}
<span *ngIf="format.key === originalFormat">(native)</span>
</label>
</div>
</div>
</header>
<gn-ui-record-form
Expand Down
14 changes: 14 additions & 0 deletions apps/metadata-converter/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { StatusComponent } from './components/status/status.component'
import { RecordOutputXmlComponent } from './components/record-output-xml/record-output-xml.component'
import { RecordFormComponent } from './components/record-form/record-form.component'
import { FORMATS, getFormatName } from './md-formats'

@Component({
selector: 'gn-ui-root',
Expand All @@ -14,11 +15,21 @@ export class AppComponent {
@ViewChild('output') outputComponent: RecordOutputXmlComponent
@ViewChild('form') formComponent: RecordFormComponent

formats = FORMATS

get originalFormat(): string {
const converter = this.statusComponent?.currentConverter
return getFormatName(converter)
}

currentFormat: string

onRecordChange(record: CatalogRecord) {
this.statusComponent.recordNative = record
}
onRecordOutputReceived(output: string) {
this.outputComponent.recordXml = output
this.currentFormat = this.originalFormat
}
onRecordNativeReceived(record: CatalogRecord) {
this.formComponent.record = record
Expand Down Expand Up @@ -52,4 +63,7 @@ export class AppComponent {
})
.catch((e) => this.statusComponent.errorLoadingFile(e.message))
}
onFormatChange(format: string) {
this.statusComponent.changeFormat(format)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,39 @@
></gn-ui-record-field-simple>
</p>
<p>
<gn-ui-record-field-group label="Owner Organisation">
<gn-ui-record-field-simple
label="Name"
[(fieldValue)]="record.ownerOrganization.name"
(confirm)="emitChangedRecord()"
></gn-ui-record-field-simple>
<gn-ui-record-field-simple
label="Description"
[(fieldValue)]="record.ownerOrganization.description"
(confirm)="emitChangedRecord()"
></gn-ui-record-field-simple>
<gn-ui-record-field-simple
label="Website"
[(fieldValue)]="record.ownerOrganization.website"
(confirm)="emitChangedRecord()"
[type]="'url'"
></gn-ui-record-field-simple>
<gn-ui-record-field-simple
label="Logo URL"
[(fieldValue)]="record.ownerOrganization.logoUrl"
(confirm)="emitChangedRecord()"
[type]="'url'"
></gn-ui-record-field-simple>
<gn-ui-record-field-group label="Owner Organization">
<gn-ui-button
*ngIf="!record.ownerOrganization"
[type]="'outline'"
(buttonClick)="addOwnerOrg()"
extraClass="m-2 py-[0.5em] px-[1em]"
>
<span class="opacity-70">Add a owner organization to this record</span>
</gn-ui-button>
<ng-container *ngIf="record.ownerOrganization">
<gn-ui-record-field-simple
label="Name"
[(fieldValue)]="record.ownerOrganization.name"
(confirm)="emitChangedRecord()"
></gn-ui-record-field-simple>
<gn-ui-record-field-simple
label="Description"
[(fieldValue)]="record.ownerOrganization.description"
(confirm)="emitChangedRecord()"
></gn-ui-record-field-simple>
<gn-ui-record-field-simple
label="Website"
[(fieldValue)]="record.ownerOrganization.website"
(confirm)="emitChangedRecord()"
[type]="'url'"
></gn-ui-record-field-simple>
<gn-ui-record-field-simple
label="Logo URL"
[(fieldValue)]="record.ownerOrganization.logoUrl"
(confirm)="emitChangedRecord()"
[type]="'url'"
></gn-ui-record-field-simple>
</ng-container>
</gn-ui-record-field-group>
</p>
<p>
Expand Down Expand Up @@ -119,7 +129,7 @@
(fieldValueChange)="set($event, 'position')"
(confirm)="emitChangedRecord()"
></gn-ui-record-field-simple>
<gn-ui-record-field-group label="Organisation">
<gn-ui-record-field-group label="Organisation" *ngIf="get().organization">
<gn-ui-record-field-simple
label="Name"
[fieldValue]="get().organization.name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,14 @@ export class RecordFormComponent implements AfterViewInit {
}
this.recordChanged.emit(this.record)
}

addOwnerOrg() {
this.record = {
...this.record,
ownerOrganization: {
name: 'My Organization',
},
}
this.recordChanged.emit(this.record)
}
}
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { findConverterForDocument } from '@geonetwork-ui/api/metadata-converter'
import { Iso191153Converter } from '@geonetwork-ui/api/metadata-converter'
import {
BaseConverter,
findConverterForDocument,
Iso191153Converter,
} from '@geonetwork-ui/api/metadata-converter'
import { FORMATS, getFormatName } from '../../md-formats'

@Component({
selector: 'gn-ui-status',
templateUrl: './status.component.html',
styleUrls: ['./status.component.css'],
})
export class StatusComponent {
_currentRecord: CatalogRecord
@Input() set recordNative(value: CatalogRecord) {
const start = performance.now()
this.status = 'Converting to ISO9139...'
this.newMetadata.emit('')
this.recordToXml(value)
.then((output) => {
this.newMetadata.emit(output)
const time = Math.round(performance.now() - start)
this.status = `Converting to ISO9139... Done (${time} ms).`
})
.catch((e) => {
this.status = `Converting to ISO9139... Failed: ${
e instanceof Error ? e.message : e
}`
console.error(e)
})
this._currentRecord = value
this.convertRecordToXml(value)
}
@Input() set currentMetadata(value: string) {
const start = performance.now()
this.status = 'Converting to native format...'
this.status = 'Converting to CatalogRecord...'
this.xmlToRecord(value)
.then((output) => {
this._currentRecord = output
this.newRecordNative.emit(output)
this.newMetadata.emit(value)
const time = Math.round(performance.now() - start)
this.status = `Converting to native format... Done (${time} ms).`
this.status = `Converting to CatalogRecord... Done (${time} ms).`
})
.catch((e) => {
this.status = `Converting to native format... Failed: ${
this.status = `Converting to CatalogRecord... Failed: ${
e instanceof Error ? e.message : e
}`
console.error(e)
Expand All @@ -48,6 +41,8 @@ export class StatusComponent {
@Output() newRecordNative = new EventEmitter<CatalogRecord>()
@Output() newMetadata = new EventEmitter<string>()

currentConverter: BaseConverter<string> = null

status = 'Standing by.'

startLoadingFile() {
Expand All @@ -64,15 +59,60 @@ export class StatusComponent {
this.status = `Reading file... Failed`
}

private recordToXml(record: CatalogRecord) {
const converter = this.referenceMetadata
? findConverterForDocument(this.referenceMetadata)
: new Iso191153Converter()
return converter.writeRecord(record, this.referenceMetadata)
public changeFormat(format: string) {
const converterClass = FORMATS[format]
if (!converterClass) {
throw new Error(`Metadata format ${format} not supported`)
}
this.referenceMetadata = ''
this.convertRecordToXml(this._currentRecord, new converterClass())
}

private convertRecordToXml(
record: CatalogRecord,
currentConverter?: BaseConverter<string>
) {
const start = performance.now()
const converter = currentConverter ?? this.currentConverter
const converterName = getFormatName(converter)
this.status = `Converting to ${converterName}...`
this.newMetadata.emit('')
this.recordToXml(record, currentConverter)
.then((output) => {
this.newMetadata.emit(output)
const time = Math.round(performance.now() - start)
this.status = `Converting to ${converterName}... Done (${time} ms).`
})
.catch((e) => {
this.status = `Converting to ${converterName}... Failed: ${
e instanceof Error ? e.message : e
}`
console.error(e)
})
}

private recordToXml(
record: CatalogRecord,
currentConverter?: BaseConverter<string>
) {
try {
this.currentConverter = currentConverter
? currentConverter
: this.referenceMetadata
? findConverterForDocument(this.referenceMetadata)
: new Iso191153Converter()
return this.currentConverter.writeRecord(record, this.referenceMetadata)
} catch (e) {
return Promise.reject(e)
}
}

private xmlToRecord(metadata: string) {
const converter = findConverterForDocument(metadata)
return converter.readRecord(metadata)
try {
this.currentConverter = findConverterForDocument(metadata)
return this.currentConverter.readRecord(metadata)
} catch (e) {
return Promise.reject(e)
}
}
}
18 changes: 18 additions & 0 deletions apps/metadata-converter/src/app/md-formats.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
BaseConverter,
DcatApConverter,
Iso191153Converter,
Iso19139Converter,
} from '@geonetwork-ui/api/metadata-converter'

export const FORMATS = {
'ISO 19139': Iso19139Converter,
'ISO 19115-3': Iso191153Converter,
'DCAT-AP': DcatApConverter,
}

export function getFormatName(converter: BaseConverter<string>): string {
return Object.keys(FORMATS).reduce((prev, key) =>
converter instanceof FORMATS[key] ? key : prev
)
}
2 changes: 2 additions & 0 deletions libs/api/metadata-converter/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ export * from './lib/iso19139'
export * from './lib/iso19115-3'
export * from './lib/find-converter'
export * from './lib/gn4'
export * from './lib/dcat-ap'
export * from './lib/xml-utils'
export * from './lib/base.converter'
Loading
Loading