diff --git a/frontend/src/components/DashboardCards.vue b/frontend/src/components/DashboardCards.vue index 4ce82ba4..076b7887 100644 --- a/frontend/src/components/DashboardCards.vue +++ b/frontend/src/components/DashboardCards.vue @@ -1,5 +1,5 @@ @@ -84,21 +119,46 @@ // needed a person put together. A filtered "recently changed" view belongs in // Reports. import DashboardCards from '@/components/DashboardCards.vue' -import { ref, onMounted } from 'vue' +import { ref, computed, onMounted } from 'vue' import { dashboardApi } from '../api' const loading = ref(true) const stats = ref({}) +// Whether the totals actually came back. Swallowing the error and rendering +// stats as {} turned a 403 into a column of confident zeros. +const summaryloaded = ref(false) + +// Where this reader can actually go, for the case where the board has nothing +// for them. Same source as the sidebar, so it is already filtered to what they +// hold - and to what the guest role reaches, when nobody is signed in. +const navitems = ref([]) + +const openable = computed( + // The dashboard itself is not somewhere to go from the dashboard. + () => navitems.value.filter((item) => item.route && item.route !== '/')) onMounted(async () => { try { - const response = await dashboardApi.summary().catch(() => ({ data: { data: {} } })) + const response = await dashboardApi.summary() stats.value = response.data.data || {} + summaryloaded.value = Object.keys(stats.value).length > 0 } catch (error) { - console.error('Dashboard load error:', error) - } finally { - loading.value = false + // A caller without assets.view is restricted, not broken, so this is not + // logged as an error - the panel offers them somewhere to go instead. + summaryloaded.value = false } + + if (!summaryloaded.value) { + // Only fetched when it is needed, so the common case costs nothing. + try { + const response = await dashboardApi.navigation() + navitems.value = response.data.data || [] + } catch (error) { + navitems.value = [] + } + } + + loading.value = false })