Introduce BackLinkViewer component and associated config #342
4 changed files with 235 additions and 116 deletions
48
src/components/BackLinkViewer.vue
Normal file
48
src/components/BackLinkViewer.vue
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
<template>
|
||||||
|
<h4 v-if="Object.keys(refRecords).length" style="margin-bottom: 1em;" >Records referencing <em>{{props.record.displayLabel}}</em>:</h4>
|
||||||
|
<div v-for="(arr, key) in refRecords" style="margin-bottom: 0.5em;">
|
||||||
|
<em>via <strong>{{makeReadable(toCURIE(key, allPrefixes, 'parts').property)}}</strong></em>:
|
||||||
|
<span v-for="r in arr">
|
||||||
|
<br> -
|
||||||
|
<NamedNodeViewer
|
||||||
|
:textVal="r.record_id"
|
||||||
|
:prefLabel="getPrefLabel(r.quad.subject, rdfDS, allPrefixes)"
|
||||||
|
:displayLabel="getRecordDisplayLabel(r.quad.subject, rdfDS, allPrefixes, configVarsMain)"
|
||||||
|
:quad="r.quad"
|
||||||
|
:targetClass="r.class_iri"
|
||||||
|
:allowLink="true"
|
||||||
|
>
|
||||||
|
</NamedNodeViewer>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
|
||||||
|
import { inject, onMounted, ref } from 'vue';
|
||||||
|
import { toCURIE, getReferencingRecords, getPrefLabel, getRecordDisplayLabel, makeReadable} from '@/modules/utils';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
record: Object,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['has-referencing-records'])
|
||||||
|
|
||||||
|
const fetchFromService = inject('fetchFromService')
|
||||||
|
const allPrefixes = inject('allPrefixes')
|
||||||
|
const rdfDS = inject('rdfDS')
|
||||||
|
const configVarsMain = inject('configVarsMain')
|
||||||
|
const refRecords = ref({});
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const arg = allPrefixes['dlthings'] + 'Thing';
|
||||||
|
await fetchFromService('get-paginated-records-constrained', arg, allPrefixes, props.record.title )
|
||||||
|
await fetchFromService('get-paginated-records-constrained', arg, allPrefixes, toCURIE(props.record.title, allPrefixes))
|
||||||
|
refRecords.value = getReferencingRecords(props.record.title, rdfDS.data.graph)
|
||||||
|
if (Object.keys(refRecords.value).length > 0) {
|
||||||
|
emit('has-referencing-records')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
@ -75,6 +75,8 @@
|
||||||
</span>
|
</span>
|
||||||
</v-card-subtitle>
|
</v-card-subtitle>
|
||||||
<v-card-text v-if="!props.formOpen" :class="mobile ? 'text-caption' : ''">
|
<v-card-text v-if="!props.formOpen" :class="mobile ? 'text-caption' : ''">
|
||||||
|
<v-row align="stretch">
|
||||||
|
<v-col :cols="showBackLinks ? 6 : 12">
|
||||||
<strong>Persistent Identifier</strong>: {{ record.title}}<br/>
|
<strong>Persistent Identifier</strong>: {{ record.title}}<br/>
|
||||||
|
|
||||||
<!-- Literal nodes -->
|
<!-- Literal nodes -->
|
||||||
|
|
@ -208,8 +210,16 @@
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
</v-col>
|
||||||
|
<v-col v-if="showBackLinks && !hideBackLinks" cols="auto" class="d-flex">
|
||||||
|
<v-divider vertical />
|
||||||
|
</v-col>
|
||||||
|
<v-col>
|
||||||
|
<BackLinkViewer v-if="firstUpdateDone && !hideBackLinks" v-show="showBackLinks" :record="record" @has-referencing-records="showBackLinks = true"></BackLinkViewer>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
<!-- Blank nodes -->
|
<!-- Blank nodes -->
|
||||||
<br />
|
<span v-if="showBackLinks && !hideBackLinks"><br /></span>
|
||||||
<v-btn
|
<v-btn
|
||||||
no-gutters
|
no-gutters
|
||||||
v-if="Object.keys(record.triples['BlankNode']).length > 0"
|
v-if="Object.keys(record.triples['BlankNode']).length > 0"
|
||||||
|
|
@ -324,6 +334,7 @@ import MoreOrLessRecordsViewer from '@/components/MoreOrLessRecordsViewer.vue';
|
||||||
import SpecialButton from '@/components/SpecialButton.vue'
|
import SpecialButton from '@/components/SpecialButton.vue'
|
||||||
import { useCompConfig } from '@/composables/useCompConfig';
|
import { useCompConfig } from '@/composables/useCompConfig';
|
||||||
import { useDisplay } from 'vuetify'
|
import { useDisplay } from 'vuetify'
|
||||||
|
import BackLinkViewer from './BackLinkViewer.vue';
|
||||||
const { mobile } = useDisplay()
|
const { mobile } = useDisplay()
|
||||||
// Define component properties
|
// Define component properties
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
|
@ -380,6 +391,14 @@ const fetchingRecords = ref(false);
|
||||||
const canEditClass = ref(false);
|
const canEditClass = ref(false);
|
||||||
const showSpecialButtons = ref(false);
|
const showSpecialButtons = ref(false);
|
||||||
const specialButtons = reactive({});
|
const specialButtons = reactive({});
|
||||||
|
const showBackLinks = ref(false);
|
||||||
|
const firstUpdateDone = ref(false);
|
||||||
|
const hideBackLinksConfig = componentConfig?.hideBackLinks;
|
||||||
|
const hideBackLinks = ref(true);
|
||||||
|
if (hideBackLinksConfig === false || Array.isArray(hideBackLinksConfig) &&
|
||||||
|
!hideBackLinksConfig.includes(toCURIE(props.classIRI, allPrefixes))) {
|
||||||
|
hideBackLinks.value = false
|
||||||
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['namedNodeSelected']);
|
const emit = defineEmits(['namedNodeSelected']);
|
||||||
function selectNamedNode(recordClass, recordPID) {
|
function selectNamedNode(recordClass, recordPID) {
|
||||||
|
|
@ -398,6 +417,7 @@ onBeforeMount(async () => {
|
||||||
fetchingRecords.value = true;
|
fetchingRecords.value = true;
|
||||||
await updateRecord(true);
|
await updateRecord(true);
|
||||||
fetchingRecords.value = false;
|
fetchingRecords.value = false;
|
||||||
|
firstUpdateDone.value = true;
|
||||||
let recordPIDprefix = toCURIE(props.quad.subject.value, allPrefixes, 'parts').prefix;
|
let recordPIDprefix = toCURIE(props.quad.subject.value, allPrefixes, 'parts').prefix;
|
||||||
if (configVarsMain['idResolvesExternally'].indexOf(recordPIDprefix) >= 0) {
|
if (configVarsMain['idResolvesExternally'].indexOf(recordPIDprefix) >= 0) {
|
||||||
resolveExternally.value = true;
|
resolveExternally.value = true;
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ const mainVarsToLoad = {
|
||||||
NodeShapeViewer: {
|
NodeShapeViewer: {
|
||||||
recordNumberStepSize: 5,
|
recordNumberStepSize: 5,
|
||||||
textTruncateWidth: "85%",
|
textTruncateWidth: "85%",
|
||||||
|
hideBackLinks: true,
|
||||||
},
|
},
|
||||||
URIEditor: {
|
URIEditor: {
|
||||||
default: "curie",
|
default: "curie",
|
||||||
|
|
|
||||||
|
|
@ -302,6 +302,56 @@ export function getSubjectQuad(subj, graph) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getReferencingRecords(objVal, graph) {
|
||||||
|
let referencingRecords = {};
|
||||||
|
const firstLevelQuads = graph.getQuads(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
namedNode(objVal),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
for (const q of firstLevelQuads) {
|
||||||
|
if (q.subject.termType === 'BlankNode') {
|
||||||
|
var secondLevelQuads = graph.getQuads(
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
q.subject,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
if (secondLevelQuads && secondLevelQuads.length) {
|
||||||
|
if (!referencingRecords.hasOwnProperty(secondLevelQuads[0].predicate.value)) {
|
||||||
|
referencingRecords[secondLevelQuads[0].predicate.value] = []
|
||||||
|
}
|
||||||
|
referencingRecords[secondLevelQuads[0].predicate.value].push({
|
||||||
|
record_id: secondLevelQuads[0].subject.value
|
||||||
|
})
|
||||||
|
var sQ = getSubjectQuad(secondLevelQuads[0].subject, graph)
|
||||||
|
if (sQ) {
|
||||||
|
referencingRecords[secondLevelQuads[0].predicate.value].at(-1).class_iri = sQ.object.value
|
||||||
|
referencingRecords[secondLevelQuads[0].predicate.value].at(-1).quad = sQ
|
||||||
|
}
|
||||||
|
if (secondLevelQuads.length > 1) {
|
||||||
|
console.error("! secondLevelQuads has length > 1 !")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!referencingRecords.hasOwnProperty(q.predicate.value)) {
|
||||||
|
referencingRecords[q.predicate.value] = []
|
||||||
|
}
|
||||||
|
referencingRecords[q.predicate.value].push({
|
||||||
|
record_id: q.subject.value
|
||||||
|
})
|
||||||
|
var sQ = getSubjectQuad(q.subject, graph)
|
||||||
|
if (sQ) {
|
||||||
|
referencingRecords[q.predicate.value].at(-1).class_iri = sQ.object.value
|
||||||
|
referencingRecords[q.predicate.value].at(-1).quad = sQ
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return referencingRecords
|
||||||
|
}
|
||||||
|
|
||||||
export function objectsEqual(obj1, obj2) {
|
export function objectsEqual(obj1, obj2) {
|
||||||
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
|
if (Object.keys(obj1).length !== Object.keys(obj2).length) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue