Skip to content

Commit

Permalink
Merge pull request #41 from psychoinformatics-de/data
Browse files Browse the repository at this point in the history
Next iteration of updates
  • Loading branch information
jsheunis authored Aug 17, 2024
2 parents 6267ea7 + aee8241 commit 7ce1cf9
Show file tree
Hide file tree
Showing 14 changed files with 499 additions and 158 deletions.
138 changes: 138 additions & 0 deletions src/components/FormEditor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<template>
<v-sheet class="pa-4" border rounded elevation="2">
<div style="display: flex;">
<h2>{{ toCURIE(props.shape_iri, shapePrefixes) }}</h2>
<span v-if="validationErrors.length" style="margin-left: auto;">
<v-menu location="end">
<template v-slot:activator="{ props }">
<v-btn color="warning" v-bind="props" density="compact" icon="mdi-alert-circle-outline"></v-btn>
</template>
<v-list>
<v-list-item v-for="e of validationErrors" @click="">
<v-list-item-title> <em>{{ e.name }}</em></v-list-item-title>
<v-list-item-subtitle>{{ e.message }}</v-list-item-subtitle>
</v-list-item>
</v-list>
</v-menu>
</span>
</div>

<br>
<p>{{ shape_obj[SHACL.description] }}</p>
<br>
<v-form ref="form" v-model="formValid" validate-on="lazy input" @submit.prevent="saveForm()" >
<NodeShapeEditor :key="props.shape_iri" :shape_iri="props.shape_iri"/>
<div style="display: flex;">
<v-btn
class="mt-2"
text="Reset"
@click="resetForm()"
style="margin-left: auto; margin-right: 1em;"
></v-btn>
<v-btn
class="mt-2"
text="Save"
type="submit"
></v-btn>
</div>
</v-form>
</v-sheet>
</template>


<script setup>
import { ref, onMounted, onBeforeMount, provide, inject, reactive} from 'vue'
import { SHACL } from '../modules/namespaces'
import { toCURIE } from '../modules/utils';
// ----- //
// Props //
// ----- //
const props = defineProps({
shape_iri: String,
})
// ---- //
// Data //
// ---- //
const add_empty_node = inject('add_empty_node')
const shapePrefixes = inject('shapePrefixes');
const nodeShapes = inject('nodeShapes')
const shape_obj = nodeShapes.value[props.shape_iri]
const form = ref(null)
const formValid = ref(null)
const fieldMap = reactive({}); // Maps element IDs to human-readable labels
const validationErrors = ref([]);
function registerRef(id, fieldData) {
fieldMap[id] = fieldData;
}
function unregisterRef(id) {
delete fieldMap[id];
}
provide('registerRef', registerRef);
provide('unregisterRef', unregisterRef);
// ----------------- //
// Lifecycle methods //
// ----------------- //
onBeforeMount(() => {
console.log(`the FormEditor component is about to be mounted.`)
})
onMounted(() => {
console.log(`the FormEditor component is now mounted.`)
})
// ------------------- //
// Computed properties //
// ------------------- //
// --------- //
// Functions //
// --------- //
async function saveForm() {
try {
validationErrors.value = []
// Await the validation result
const validationResult = await form.value.validate();
if (validationResult.valid) {
// If the form is valid, proceed with form submission
add_empty_node(props.shape_iri);
} else {
console.log("Still some validation errors, bro");
validationResult.errors.forEach(error => {
const id = error.id;
const fieldData = fieldMap[id];
if (fieldData) {
validationErrors.value.push({
name: fieldData.name,
message: error.errorMessages.join(', '),
});
}
});
}
} catch (error) {
console.error("Validation failed:", error);
}
}
function resetForm() {
form.value.reset()
}
</script>
91 changes: 73 additions & 18 deletions src/components/InstancesSelectEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,53 @@
<v-autocomplete
density="compact"
variant="outlined"
label="(instances select editor)"
label="select an item"
v-model="triple_object"
:items="instanceItems"
validate-on="lazy input"
:rules="rules"
item-value="value"
item-text="title"
return-object
ref="fieldRef"
:id="inputId"
>

<template v-slot:item="data">
<v-list-item @click="console.log('add new item')" v-if="data.item.props.isButton">
<template v-slot:prepend>
<v-icon icon="item.icon">mdi-plus-box</v-icon>
</template>
<v-list-item-title>{{ data.item.title }}</v-list-item-title>
</v-list-item>
<v-list-item @click="selectItem(data.item)" v-else>
<v-list-item-title>{{ data.item.title }}</v-list-item-title>
<v-list-item-subtitle>{{ data.item.props.subtitle }}</v-list-item-subtitle>
</v-list-item>
<div v-if="data.item.props.isButton">
<v-list-item>
<v-list-item-title>
<v-menu location="end">
<template v-slot:activator="{ props }">
<v-btn variant="tonal" v-bind="props">{{ data.item.title }} &nbsp;&nbsp; <v-icon icon="item.icon">mdi-play</v-icon></v-btn>
</template>

<v-list>
<v-list-item v-for="item in propClassList" @click="add_empty_node(item.value)">
<v-list-item-title>{{ item.title }}</v-list-item-title>
<v-dialog activator="parent" max-width="700">
<template v-slot:default="{ isActive }">
<FormEditor :shape_iri="item.value"></FormEditor>
</template>
</v-dialog>
</v-list-item>
</v-list>
</v-menu>

</v-list-item-title>
</v-list-item>
</div>
<div v-else>
<v-list-item @click="selectItem(data.item)">
<v-list-item-title>{{ data.item.title }}</v-list-item-title>
<v-list-item-subtitle>{{ data.item.props.subtitle }}</v-list-item-subtitle>
</v-list-item>
</div>
</template>
</v-autocomplete>



</template>

<script setup>
Expand All @@ -33,6 +57,9 @@
import rdf from 'rdf-ext'
import {SHACL, RDF, RDFS, DLTHING, XSD} from '@/modules/namespaces'
import { toCURIE } from '../modules/utils';
import { useRegisterRef } from '../composables/refregister';
// ----- //
// Props //
Expand All @@ -50,16 +77,21 @@
// ---- //
const formData = inject('formData');
const propertyGroups = inject('propertyGroups');
const nodeShapes = inject('nodeShapes');
const graphData = inject('graphData');
const add_empty_node = inject('add_empty_node');
const graphPrefixes = inject('graphPrefixes');
const shapePrefixes = inject('shapePrefixes');
const classPrefixes = inject('classPrefixes');
const allPrefixes = {...shapePrefixes, ...graphPrefixes, ...classPrefixes};
const classData = inject('classData');
const { rules } = useRules(props.property_shape)
var propClass = ref(null)
const combinedQuads = reactive([])
const instanceItems = reactive([])
const inputId = `input-${Date.now()}`;
const { fieldRef } = useRegisterRef(inputId, props);
// ------------------- //
// Computed properties //
// ------------------- //
Expand All @@ -85,13 +117,12 @@
// ---
// TODO: what should the correct default value be here?
propClass.value = props.property_shape[SHACL.class.value] ?? false
let allprefixes = {...shapePrefixes, ...graphPrefixes, ...classPrefixes};
// find nodes with predicate rdf:type and object being the property class
var quads = getLiteralAndNamedNodes(
graphData,
rdf.namedNode(RDF.type),
propClass.value,
allprefixes
allPrefixes
)
// then find nodes with predicate rdfs:subClassOf and object being the property class
// TODO: here we are only using a named node for the object because this is how the
Expand All @@ -105,7 +136,7 @@
var myArr = []
Array.from(subClasses).forEach(quad => {
const cl = quad.subject.value
myArr = myArr.concat(getLiteralAndNamedNodes(graphData, rdf.namedNode(RDF.type), cl, allprefixes))
myArr = myArr.concat(getLiteralAndNamedNodes(graphData, rdf.namedNode(RDF.type), cl, allPrefixes))
});
// Then combine all quad arrays
const combinedQuads = quads.concat(myArr);
Expand All @@ -126,12 +157,36 @@
{
title: quad.subject.value + extra,
value: quad.subject.value,
props: { subtitle: toCURIE(quad.object.value, allprefixes) },
props: { subtitle: toCURIE(quad.object.value, allPrefixes) },
}
)
});
})
const propClassList = computed(() => {
var items = []
// first add main property class
items.push(
{
title: toCURIE(propClass.value, allPrefixes),
value: propClass.value
}
)
const subClasses = rdf.grapoi({ dataset: classData })
.hasOut(rdf.namedNode(RDFS.subClassOf.value), rdf.namedNode(propClass.value))
.quads();
Array.from(subClasses).forEach(quad => {
items.push(
{
title: toCURIE(quad.subject.value, allPrefixes),
value: quad.subject.value
}
)
});
return items
})
// --------- //
// Functions //
// --------- //
Expand All @@ -152,9 +207,9 @@
function selectItem(item) {
triple_object.value = item.value;
fieldRef.value.blur();
}
</script>
<!-- Component matching logic -->
Expand Down
31 changes: 9 additions & 22 deletions src/components/MainForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,10 @@
<v-row align="start" style="flex-wrap: nowrap" no-gutters>
<!-- Display selected form -->
<v-col cols="6">
<h3>Selected form</h3>
<v-sheet class="pa-4" border rounded elevation="2">
<span v-if="selectedIRI && prefixes_ready">
<v-form ref="form" validate-on="submit lazy" @submit.prevent="saveForm()" >
<NodeShapeEditor :key="selectedIRI" :shape_iri="selectedIRI" :shape_obj="selectedShape" :prop_groups="propertyGroups"/>

<div style="display: flex;">
<v-btn
class="mt-2"
text="Reset"
@click="resetForm()"
style="margin-left: auto; margin-right: 1em;"
></v-btn>
<v-btn
class="mt-2"
text="Save"
type="submit"
></v-btn>
</div>
</v-form>
</span>
</v-sheet>
<span v-if="selectedIRI && prefixes_ready">
<h3>Selected form</h3>
<FormEditor :key="selectedIRI" :shape_iri="selectedIRI"></FormEditor>
</span>
</v-col>
<!-- Display entered form data -->
<v-col class="ml-6">
Expand Down Expand Up @@ -115,6 +97,11 @@
provide('shapePrefixes', shapePrefixes)
provide('editorMatchers', editorMatchers)
provide('defaultEditor', defaultEditor)
provide('nodeShapes', nodeShapes)
provide('propertyGroups', propertyGroups)
provide('shapesDataset', shapesDataset)
provide('prefixArray', prefixArray)
provide('nodeShapeIRIs', nodeShapeIRIs)
// ----------------- //
Expand Down
Loading

0 comments on commit 7ce1cf9

Please sign in to comment.