Skip to content
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
3 changes: 2 additions & 1 deletion nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ export default defineNuxtConfig({
NUXT_OIDC_CLIENT_ID: process.env.NUXT_OIDC_CLIENT_ID,
AUTH_ORIGIN: process.env.AUTH_ORIGIN,
NEXTAUTH_URL: process.env.NEXTAUTH_URL,
ZOO_OGCAPI_REQUIRES_BEARER_TOKEN: process.env.ZOO_OGCAPI_REQUIRES_BEARER_TOKEN
ZOO_OGCAPI_REQUIRES_BEARER_TOKEN: process.env.ZOO_OGCAPI_REQUIRES_BEARER_TOKEN,
SUBSCRIBERURL: process.env.SUBSCRIBERURL,
},
}
})
11,742 changes: 4,979 additions & 6,763 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@
"@sidebase/nuxt-auth": "^0.9.0",
"cookie": ">=0.7.0",
"crypto-js": "^4.2.0",
"cwl-svg": "^2.1.14",
"cwlts": "^1.23.10",
"html2canvas": "^1.4.1",
"js-yaml": "^4.1.1",
"nanoid": ">=5.0.9",
"next-auth": "^4.21.1",
"nuxt": "^3.15.4",
Expand Down
152 changes: 152 additions & 0 deletions pages/processes/[processId].vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { useHead } from '#imports'
import { ref, onMounted, watch, reactive } from 'vue'
import { useRoute } from 'vue-router'
import { useRuntimeConfig } from '#imports'
Expand All @@ -9,6 +10,7 @@ import HelpDialog from '@/components/help/HelpDialog.vue'
import processIdHelp from '@/components/help/processIdHelp.js'



const {
params: { processId }
} = useRoute()
Expand Down Expand Up @@ -100,6 +102,7 @@ const typeLabel = (input: any, valForInputId: any) => {
return input?.schema?.type || 'literal'
}


const fetchData = async () => {
try {
data.value = await $fetch(`${config.public.NUXT_ZOO_BASEURL}/ogc-api/processes/${processId}`, {
Expand All @@ -108,6 +111,8 @@ const fetchData = async () => {
}
})



if (data.value && data.value.inputs) {
for (const [key, input] of Object.entries(data.value.inputs)) {
if (input.minOccurs === undefined && input.maxOccurs === undefined) {
Expand Down Expand Up @@ -211,6 +216,94 @@ const fetchData = async () => {
}
}


watch(
() => data.value,
(val) => {
if (!val) return

const rawMetadata = val.metadata || []

// Extract items by role
const extractByRole = (role) =>
rawMetadata
.filter(md => md.role === role)
.map(md => md.value)

// Authors (may be multiple)
const authors = extractByRole("https://schema.org/author")
.map(a => ({
"@type": a["@type"] || "Person",
"name": a.name || a.fullName || ""
}))

// Contributors
const contributors = extractByRole("https://schema.org/contributor")
.map(c => ({
"@type": c["@type"] || "Person",
"name": c.name || c.fullName || ""
}))

// Organizations
const organizations = extractByRole("https://schema.org/organization")
.map(org => ({
"@type": "Organization",
"name": org.name || ""
}))

// Additional metadata (anything NOT author/contributor/organization)
const skipRoles = [
"https://schema.org/author",
"https://schema.org/contributor",
"https://schema.org/organization"
]

const additionalProps = rawMetadata
.filter(md => !skipRoles.includes(md.role))
.map(md => ({
"@type": "PropertyValue",
"name": md.role,
"value": md.value
}))

// Build final JSON-LD
const jsonLd = {
"@context": "https://schema.org",
"@type": "SoftwareSourceCode",
"name": val.id,
"description": val.description,
"softwareVersion": val.version || null,
"keywords": val.keywords || [],
"identifier": processId,
"url": `http://localhost:3058/processes/${processId}`,

// New metadata mapping
"author": authors,
"contributor": contributors,
"provider": organizations.length ? organizations[0] : {
"@type": "Organization",
"name": "ZOO-Project"
},

"additionalProperty": additionalProps
}

// Inject JSON-LD into <head>
useHead({
script: [
{
type: "application/ld+json",
children: JSON.stringify(jsonLd)
}
]
})
},
{ immediate: true }
)




onMounted(() => {
fetchData()
})
Expand Down Expand Up @@ -587,6 +680,65 @@ const removeInputField = (inputId: string, index: number) => {
<div class="text-subtitle1 text-grey-7">
{{ data.description }}
</div>
<q-card-section class="q-pa-md bg-grey-1 rounded-borders q-mt-md">

<!-- Version -->
<div class="row q-mb-sm">
<div class="col-3 text-grey-7 text-weight-bold">Version</div>
<div class="col">
{{ data.version || '—' }}
</div>
</div>

<!-- Keywords -->
<div class="row q-mb-sm">
<div class="col-3 text-grey-7 text-weight-bold">Keywords</div>
<div class="col">
<span v-if="data.keywords?.length">
{{ data.keywords.join(', ') }}
</span>
<span v-else>—</span>
</div>
</div>

<!-- Metadata -->
<div class="row q-mb-sm">
<div class="col-12 text-grey-7 text-weight-bold q-mb-xs">Additional Metadata</div>

<div v-if="data.metadata?.length" class="col-12">

<div v-for="(md, index) in data.metadata" :key="index" class="q-pa-sm bg-white rounded-borders q-mb-sm shadow-1">

<!-- Detect Person -->
<div v-if="md.value && typeof md.value === 'object' && md.value['@type'] === 'Person'">
<div class="text-weight-bold text-primary">👤 {{ md.title || 'Person' }}</div>
<div class="q-mt-xs">
<div><strong>Name:</strong> {{ md.value.name }}</div>
<div v-if="md.value.role"><strong>Role:</strong> {{ md.value.role }}</div>
<div v-if="md.value.email"><strong>Email:</strong> {{ md.value.email }}</div>
<div v-if="md.value.affiliation"><strong>Affiliation:</strong> {{ md.value.affiliation }}</div>
</div>
</div>

<!-- Default metadata -->
<div v-else>
<div class="text-weight-bold">{{ md.title || md.role }}</div>
<div class="text-grey-8">{{ md.value }}</div>
</div>

</div>

</div>


<div v-else class="col-12">
</div>
</div>

</q-card-section>


<q-separator class="q-mt-md" />
</div>

Expand Down
Loading