From 0a262d3ef1b46b9a31c0372f0239239b3071bc01 Mon Sep 17 00:00:00 2001 From: Stefan Peters Date: Tue, 9 Jul 2024 10:36:21 +0200 Subject: [PATCH] ItemView: Add error handling (#36) Shows errors if scheme, top concepts, or concept data could not be loaded. --- locale.json | 8 +++++ src/client/views/ItemView.vue | 66 ++++++++++++++++++++++++++++++----- 2 files changed, 66 insertions(+), 8 deletions(-) diff --git a/locale.json b/locale.json index 9fbac87..c998b20 100644 --- a/locale.json +++ b/locale.json @@ -10,6 +10,10 @@ "conceptSearch": "Suche nach Konzept", "license": "Lizenz", "distributions": "Distributionen", + "error": "Fehler", + "schemeError": "Vokabular konnte nicht gefunden werden.", + "loadTopError": "@:error{':'} Oberkonzepte konnten nicht geladen werden.", + "loadConceptError": "Konzeptdetails konnten nicht geladen werden. Entweder existiert das Konzept nicht oder es gibt Probleme beim Zugriff auf das Backend.", "searchInVocabulary": "in {voc} suchen" }, "en": { @@ -23,6 +27,10 @@ "conceptSearch": "Searching for concept", "license": "License", "distributions": "Distributions", + "error": "Error", + "schemeError": "Vocabulary could not be found.", + "loadTopError": "@:error{':'} Top concepts could not be loaded.", + "loadConceptError": "Concept details could not be loaded. Either the concept does not exist, or there are issues with the backend.", "searchInVocabulary": "search in {voc}" } } diff --git a/src/client/views/ItemView.vue b/src/client/views/ItemView.vue index d15fbed..26b4f1f 100644 --- a/src/client/views/ItemView.vue +++ b/src/client/views/ItemView.vue @@ -3,7 +3,7 @@ import config from "@/config.js" import * as jskos from "jskos-tools" import { AutoLink, LicenseInfo } from "jskos-vue" import { schemes, registry, loadTop, loadNarrower, loadConcept, loadAncestors, saveConcept, formats } from "@/store.js" -import { computed, ref, watch } from "vue" +import { computed, ref, reactive, watch } from "vue" import { useRoute, useRouter } from "vue-router" import { utils } from "jskos-vue" import MapView from "@/components/MapView.vue" @@ -14,8 +14,15 @@ const router = useRouter() const conceptTreeRef = ref(null) +const errors = reactive({ + schemeError: false, + loadConceptError: false, + loadTopError: false, +}) + +const schemeUri = computed(() => route.params.voc.match(/^https?:\/\//) ? route.params.voc : `${config.namespace}${route.params.voc}/`) const scheme = computed(() => { - return schemes.value?.find(s => jskos.compare(s, { uri: route.params.voc.match(/^https?:\/\//) ? route.params.voc : `${config.namespace}${route.params.voc}/` })) + return schemes.value?.find(s => jskos.compare(s, { uri: schemeUri.value })) }) const uri = computed(() => scheme.value && (route.params.id && `${config.namespace}${route.params.voc}/${route.params.id}` || route.query.uri)) @@ -35,13 +42,21 @@ const hierarchyLoading = ref(true) let topLoadingPromise = null // Load top concepts when scheme is ready -watch(scheme, async () => { +watch([schemes, scheme], async () => { + errors.loadTopError = false if (scheme.value && (!scheme.value?.topConcepts || scheme.value?.topConcepts?.includes(null))) { topLoadingPromise = loadTop(scheme.value) } + if (scheme.value) { + errors.schemeError = false + } else if (schemes.value?.length) { + console.error(`Scheme ${schemeUri.value} could not be found.`) + errors.schemeError = true + } },{ immediate: true }) watch(uri, async (value, prevValue) => { + errors.loadConceptError = false if (value && value !== prevValue) { let shouldScroll = true const openAndScroll = () => { @@ -82,9 +97,23 @@ watch(uri, async (value, prevValue) => { const tabsVueComponent = document.getElementsByClassName("jskos-vue-tabs")[0]?.__vueParentComponent tabsVueComponent?.proxy?.activateTab(0) // Wait for top concepts before doing anything else - topLoadingPromise && await topLoadingPromise + try { + topLoadingPromise && await topLoadingPromise + } catch (error) { + console.error(`Error loading top concepts for ${scheme.value?.uri}:`, error) + errors.loadTopError = true + } // Load concept data - const loadedConcept = await loadConcept(value, scheme.value) + let loadedConcept + try { + loadedConcept = await loadConcept(value, scheme.value) + } catch (error) { + console.error(`Error loading concept ${value}:`, error) + errors.loadConceptError = true + conceptLoading.value = false + hierarchyLoading.value = false + return + } // Abort if concept has changed in the meantime if (value !== uri.value) { return @@ -111,9 +140,14 @@ const topConcepts = computed(() => { +
+
+ {{ $t("error") }}: {{ uri }} +
+ {{ $t("loadConceptError") }} +