Skip to content

Commit

Permalink
Merge branch 'main' into feature/object-page-anno-ttl
Browse files Browse the repository at this point in the history
  • Loading branch information
jamiefeiss committed Aug 31, 2023
2 parents f974084 + f7c486d commit 0bf84d3
Show file tree
Hide file tree
Showing 34 changed files with 1,485 additions and 442 deletions.
3 changes: 3 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
## ---------------------------------------
VITE_SIDENAV=true
VITE_ENABLED_PREZS=CatPrez,SpacePrez,VocPrez
VITE_PER_PAGE=20
VITE_CONCEPT_PER_PAGE=100
VITE_ENABLE_SCORES=true

## ---------------------------------------
## MAP DISPLAY DEFAULT SETTINGS
Expand Down
3 changes: 3 additions & 0 deletions env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
interface ImportMetaEnv {
readonly VITE_SIDENAV: string; // true | false
readonly VITE_ENABLED_PREZS: string; // CatPrez | SpacePrez | VocPrez comma separated
readonly VITE_ENABLE_SCORES: string; // true | false
readonly VITE_PER_PAGE: number;
readonly VITE_CONCEPT_PER_PAGE: number;
readonly VITE_API_BASE_URL: string;
readonly VITE_MAP_SETTINGS_API_KEY: string;
readonly VITE_MAP_SETTINGS_OPTIONS_CENTER_LAT: number;
Expand Down
452 changes: 370 additions & 82 deletions package-lock.json

Large diffs are not rendered by default.

40 changes: 20 additions & 20 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ const ui = useUiStore();
const { data, profiles, loading, error, doRequest } = useGetRequest();
const { data: profData, profiles: profProfiles, loading: profLoading, error: profError, doRequest: profDoRequest } = useGetRequest();
const { store, prefixes, parseIntoStore, qname } = useRdfStore();
const { store: profStore, prefixes: profPrefixes, parseIntoStore: profParseIntoStore, qname: profQname } = useRdfStore();
const { store: combinedStore, prefixes: combinedPrefixes, parseIntoStore: combinedParseIntoStore, qname: combinedQname } = useRdfStore();
const { store, prefixes, parseIntoStore, qnameToIri } = useRdfStore();
const { store: profStore, prefixes: profPrefixes, parseIntoStore: profParseIntoStore, qnameToIri: profQnameToIri } = useRdfStore();
const { store: combinedStore, prefixes: combinedPrefixes, parseIntoStore: combinedParseIntoStore, qnameToIri: combinedQnameToIri } = useRdfStore();
document.title = ui.pageTitle;
Expand All @@ -47,8 +47,8 @@ onMounted(() => {
token: q.object.value.replace("/profiles/", ""),
link: `${apiBaseUrl}${q.object.value}`
}
}, subject, namedNode(profQname("prez:link")), null, null);
}, namedNode(profQname("a")), namedNode(profQname("prof:Profile")), null);
}, subject, namedNode(profQnameToIri("prez:link")), null, null);
}, namedNode(profQnameToIri("a")), namedNode(profQnameToIri("prof:Profile")), null);
// promise.all request for each profile in parallel
Promise.all(Object.values(profileUris).map(p => fetch(p.link).then(r => r.text()))).then(values => {
Expand All @@ -72,27 +72,27 @@ onMounted(() => {
explanationPredicates: []
};
combinedStore.value.forEach(q => {
if (q.predicate.value === combinedQname("dcterms:title")) {
if (q.predicate.value === combinedQnameToIri("dcterms:title")) {
p.title = q.object.value;
} else if (q.predicate.value === combinedQname("dcterms:description")) {
} else if (q.predicate.value === combinedQnameToIri("dcterms:description")) {
p.description = q.object.value;
// } else if (q.predicate.value === combinedQname("dcterms:identifier")) {
// } else if (q.predicate.value === combinedQnameToIri("dcterms:identifier")) {
// p.token = q.object.value;
} else if (q.predicate.value === combinedQname("altr-ext:hasResourceFormat")) {
} else if (q.predicate.value === combinedQnameToIri("altr-ext:hasResourceFormat")) {
p.mediatypes.push(q.object.value);
} else if (q.predicate.value === combinedQname("altr-ext:hasDefaultResourceFormat")) {
} else if (q.predicate.value === combinedQnameToIri("altr-ext:hasDefaultResourceFormat")) {
p.defaultMediatype = q.object.value;
} else if (q.predicate.value === combinedQname("altr-ext:hasLabelPredicate")) {
} else if (q.predicate.value === combinedQnameToIri("altr-ext:hasLabelPredicate")) {
p.labelPredicates.push(q.object.value);
} else if (q.predicate.value === combinedQname("altr-ext:hasDescriptionPredicate")) {
} else if (q.predicate.value === combinedQnameToIri("altr-ext:hasDescriptionPredicate")) {
p.descriptionPredicates.push(q.object.value);
} else if (q.predicate.value === combinedQname("altr-ext:hasExplanationPredicate")) {
} else if (q.predicate.value === combinedQnameToIri("altr-ext:hasExplanationPredicate")) {
p.explanationPredicates.push(q.object.value);
}
}, subject, null, null, null);
p.mediatypes.sort((a, b) => Number(b === p.defaultMediatype) - Number(a === p.defaultMediatype));
profs.push(p);
}, namedNode(combinedQname("a")), namedNode(combinedQname("prof:Profile")), null);
}, namedNode(combinedQnameToIri("a")), namedNode(combinedQnameToIri("prof:Profile")), null);
ui.profiles = profs.reduce<{[namespace: string]: Profile}>((obj, prof) => (obj[prof.namespace] = prof, obj), {}); // {uri: {...}, ...}
});
Expand All @@ -104,7 +104,7 @@ onMounted(() => {
parseIntoStore(data.value);
// get API version
const version = store.value.getObjects(null, qname("prez:version"), null)[0];
const version = store.value.getObjects(null, qnameToIri("prez:version"), null)[0];
ui.apiVersion = version.value;
// get search methods per flavour
Expand All @@ -113,14 +113,14 @@ onMounted(() => {
let flavour = "";
let methods: string[] = [];
store.value.forEach(q => {
if (q.predicate.value === qname("a")) {
flavour = q.object.value.split(`${qname('prez:')}`)[1];
} else if (q.predicate.value === qname("prez:availableSearchMethod")) {
methods.push(q.object.value.split(`${qname('prez:')}`)[1]);
if (q.predicate.value === qnameToIri("a")) {
flavour = q.object.value.split(`${qnameToIri('prez:')}`)[1];
} else if (q.predicate.value === qnameToIri("prez:availableSearchMethod")) {
methods.push(q.object.value.split(`${qnameToIri('prez:')}`)[1]);
}
}, object, null, null, null);
searchMethods[flavour] = methods;
}, null, qname("prez:enabledPrezFlavour"), null);
}, null, qnameToIri("prez:enabledPrezFlavour"), null);
ui.searchMethods = searchMethods;
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/components/BaseModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ onUnmounted(() => {
$borderColor: #c9c9c9;
display: flex;
flex-direction: column;
padding: 8px;
padding: 16px;
gap: 8px;
overflow-y: auto;
border-top: 1px solid $borderColor;
Expand Down
93 changes: 93 additions & 0 deletions src/components/CircleProgress.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<script lang="ts" setup>
import { computed } from "vue";
// import ToolTip from "@/components/ToolTip.vue";
const props = defineProps<{
value?: number;
max?: number;
percentage?: number;
label?: string;
tickWhenComplete?: boolean;
gradient?: boolean;
// tooltip?: boolean;
}>();
const percent = computed(() => {
if (props.value !== undefined && props.max !== undefined) {
return props.value / props.max * 100;
} else if (props.percentage !== undefined) {
return props.percentage;
} else {
return 0;
}
});
const percentColour = computed(() => {
if (percent.value < 34) {
return "230, 0, 0"; // red
} else if (percent.value <= 80) {
return "255, 165, 0"; // orange
} else if (percent.value < 100) {
return "175, 230, 0"; // light yellowish-green
} else if (percent.value == 100) {
return "0, 230, 38"; // green
} else {
return "128, 128, 128"; // grey, invalid
}
});
const percentColourHsl = computed(() => {
const startColour = 0; // red
const endColour = 75; // light yellowish-green
const completeColour = 130; // green
const hue = percent.value === 100 ? completeColour : (endColour - startColour) * percent.value / 100;
return `${hue}, 100%, 45%`;
// 0, 0%, 50% // invalid
});
</script>

<template>
<!-- <component :is="props.tooltip ? ToolTip : 'slot'"> -->
<div :class="`circle-progress`" :style="{ background: `conic-gradient(${props.gradient ? `hsl(${percentColourHsl}` : `rgb(${percentColour}`}) ${percent}%, 0, ${props.gradient ? `hsla(${percentColourHsl}` : `rgba(${percentColour}`}, 0.2) ${100 - percent}%)` }">
<div class="circle-overlay">
<span class="circle-value">
<template v-if="props.label">{{ props.label }}</template>
<template v-else-if="props.tickWhenComplete && percent === 100"><i class="fa-solid fa-check"></i></template>
<template v-else-if="props.value !== undefined && props.max !== undefined">{{ props.value }}/{{ props.max }}</template>
<template v-else-if="props.percentage !== undefined">{{ props.percentage }}%</template>
</span>
</div>
</div>
<!-- <template v-if="props.tooltip" #text>
<template v-if="props.value !== undefined && props.max !== undefined">{{ props.value }}/{{ props.max }}</template>
<template v-else-if="props.percentage !== undefined">{{ props.percentage }}%</template>
</template>
</component> -->
</template>

<style lang="scss" scoped>
.circle-progress {
border-radius: 50%;
height: 100%;
width: 100%;
aspect-ratio: 1;
position: relative;
.circle-overlay {
border-radius: 50%;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset: 0.5rem;
.circle-value {
font-size: 0.9em;
}
}
}
</style>
67 changes: 61 additions & 6 deletions src/components/ConceptComponent.vue
Original file line number Diff line number Diff line change
@@ -1,25 +1,80 @@
<script lang="ts" setup>
import { ref, watch } from "vue";
import { ref, computed, watch, inject } from "vue";
import { RouterLink } from "vue-router";
import type { ConceptProps } from "@/types";
import { type ConceptProps, conceptPerPageConfigKey } from "@/types";
const conceptPerPage = inject(conceptPerPageConfigKey) as number;
const props = defineProps<ConceptProps>();
const emit = defineEmits<{
(e: "getNarrowers", obj: {
iriPath: string;
link: string;
page: number;
}): void;
}>();
const collapse = ref(true);
const iriPath = computed(() => {
return props.parentPath === "" ? props.iri : `${props.parentPath}|${props.iri}`;
});
watch(() => props.collapseAll, (newValue, oldValue) => {
collapse.value = newValue;
});
function toggleCollapse() {
if (collapse.value && props.children.length === 0 && props.childrenCount > 0 && props.doNarrowerEmits) {
emit("getNarrowers", {
iriPath: iriPath.value,
link: props.link,
page: 1
});
}
collapse.value = !collapse.value;
}
function loadMoreNarrowers() {
emit("getNarrowers", {
iriPath: iriPath.value,
link: props.link,
page: Math.round(props.children.length / conceptPerPage) + 1
});
}
</script>

<template>
<div class="concept-top">
<button v-if="props.children" class="concept-left btn outline" @click="collapse = !collapse"><i :class="`fa-regular fa-${collapse ? 'plus' : 'minus'}`"></i></button>
<button
v-if="props.childrenCount > 0"
class="concept-left btn outline"
@click="toggleCollapse"
>
<i :class="`fa-regular fa-${collapse ? 'plus' : 'minus'}`"></i>
</button>
<div v-else class="concept-left"></div>
<RouterLink class="concept" :to="props.link">{{ props.title || props.iri }}</RouterLink>
<RouterLink class="concept" :to="props.link">{{ props.title || props.iri }}</RouterLink> <span v-if="!!props.color" :style="{color: props.color}" class="fa-solid fa-circle fa-2xs"></span>
</div>
<div v-if="props.children" :class="`concept-children ${collapse ? 'collapse' : ''}`">
<ConceptComponent v-for="concept in props.children" v-bind="concept" :baseUrl="props.baseUrl" :collapseAll="props.collapseAll" />
<div v-if="props.childrenCount > 0" :class="`concept-children ${collapse ? 'collapse' : ''}`">
<ConceptComponent
v-for="concept in props.children"
v-bind="concept"
:baseUrl="props.baseUrl"
:collapseAll="props.collapseAll"
:parentPath="iriPath"
@getNarrowers="emit('getNarrowers', $event)"
:doNarrowerEmits="props.doNarrowerEmits"
/>
<button
v-if="props.children.length > 0 && props.childrenCount > props.children.length && props.doNarrowerEmits"
class="btn outline sm"
@click="loadMoreNarrowers"
:style="{marginLeft: '26px'}"
>
Load more
</button>
</div>
</template>

Expand Down
9 changes: 7 additions & 2 deletions src/components/MapClient.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,12 @@ watch(mapRef, googleMap => {
features = []
results.forEach(result=>{
try {
const geoJson = wktToGeoJSON(result.wkt)
// The terraformer wkt parser does not handle CRS values as IRIs.
// The following regex strips out any IRIs in the WKT.
// Note that the regex does not conform to IRIs but simply strips
// out anything that is surrounded by angled brackets.
let wkt = result.wkt.replace(/(<([^>]+)>)/gi, "")
const geoJson = wktToGeoJSON(wkt)
const featureGeoJson = {
type: 'Feature',
geometry: geoJson,
Expand All @@ -111,7 +116,7 @@ watch(mapRef, googleMap => {
bounds.extend(latlng);
});
});
setShape(result.wkt)
setShape(wkt)
map.fitBounds(bounds);
} catch (ex) {
// can happen if we're unable to parse the result, just consoled out for now
Expand Down
20 changes: 10 additions & 10 deletions src/components/PaginationComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,42 @@ import { ref, computed, watch } from "vue";
import { RouterLink } from "vue-router";
import router from "@/router";
const PER_PAGE = 10;
const props = defineProps<{
totalCount: number;
perPage?: number;
perPage: number;
currentPage: number;
url: string;
}>();
const pageDropdown = ref(props.currentPage);
const perPage = ref(Number(props.perPage));
const totalPages = computed(() => {
const pageCount = props.perPage || PER_PAGE;
return Math.ceil(props.totalCount / pageCount);
return Math.ceil(props.totalCount / perPage.value);
});
watch(pageDropdown, (newValue, oldValue) => {
if (newValue !== oldValue) {
router.push(`${props.url}?page=${newValue}${props.perPage ? `&per_page=${props.perPage}` : ''}`);
router.push(`${props.url}?page=${newValue}&per_page=${perPage.value}`);
}
});
// watcher for reloading when selecting per_page when dropdown is added
</script>

<template>
<div class="pagination">
<RouterLink
v-if="props.currentPage > 2"
:to="`${props.url}?page=1${props.perPage ? `&per_page=${props.perPage}` : ''}`"
:to="`${props.url}?page=1&per_page=${perPage}`"
class="btn outline pagination-btn"
>
1
</RouterLink>
<div v-if="props.currentPage > 3"><i class="fa-regular fa-ellipsis"></i></div>
<RouterLink
v-if="props.currentPage > 1"
:to="`${props.url}?page=${props.currentPage - 1}${props.perPage ? `&per_page=${props.perPage}` : ''}`"
:to="`${props.url}?page=${props.currentPage - 1}&per_page=${perPage}`"
class="btn outline pagination-btn"
>
{{ props.currentPage - 1 }}
Expand All @@ -48,15 +48,15 @@ watch(pageDropdown, (newValue, oldValue) => {
</select>
<RouterLink
v-if="props.currentPage < totalPages"
:to="`${props.url}?page=${props.currentPage + 1}${props.perPage ? `&per_page=${props.perPage}` : ''}`"
:to="`${props.url}?page=${props.currentPage + 1}&per_page=${perPage}`"
class="btn outline pagination-btn"
>
{{ props.currentPage + 1 }}
</RouterLink>
<div v-if="props.currentPage < totalPages - 2"><i class="fa-regular fa-ellipsis"></i></div>
<RouterLink
v-if="props.currentPage < totalPages - 1"
:to="`${props.url}?page=${totalPages}${props.perPage ? `&per_page=${props.perPage}` : ''}`"
:to="`${props.url}?page=${totalPages}&per_page=${perPage}`"
class="btn outline pagination-btn"
>
{{ totalPages }}
Expand Down
Loading

0 comments on commit 0bf84d3

Please sign in to comment.