Offer the search box to whoever can actually search
The sidebar box was drawn for anyone signed in, on the reasoning that offering it to a signed-out reader gives them a control that can only answer 401. That stopped being the right test when the guest role became able to hold assets.view: the box was hidden from exactly the visitor the grant was reopened for, and a guest could reach search only by typing /search?q= by hand. The client cannot decide this. Its hasPermission getter reads the signed-in user's permission list and a guest has no user at all, so asking it about a guest answers no for everyone. get_navigation already had the problem and already solved it by letting the server decide, so capabilities does the same thing and reports what the CALLER holds. It reports booleans about the caller and never what the guest role holds in general, so it tells an anonymous reader nothing the rendered page does not. Public because it is the pre-login call that decides whether the box is drawn at all. Members who lack assets.view now lose a box that only ever 401'd for them. On a failed call the box stays hidden rather than falling back to the old signed-in test, which would put it back in front of those same members. Scope: product
This commit is contained in:
@@ -536,6 +536,9 @@ export const dashboardApi = {
|
||||
},
|
||||
navigation() {
|
||||
return api.get('/dashboard/navigation')
|
||||
},
|
||||
capabilities() {
|
||||
return api.get('/dashboard/capabilities')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Global search is authenticated; offering the box to a signed-out
|
||||
reader gives them a control that can only answer 401. -->
|
||||
<div v-if="authStore.isAuthenticated" class="sidebar-search">
|
||||
<!-- Drawn only for a caller who can actually search. The server
|
||||
answers that, because a guest has no user object here and
|
||||
hasPermission would say no for the very visitor the guest grant
|
||||
exists to serve. Members who lack assets.view lose a box that only
|
||||
ever answered 401 to them. -->
|
||||
<div v-if="cansearch" class="sidebar-search">
|
||||
<input
|
||||
v-model="searchQuery"
|
||||
type="text"
|
||||
@@ -145,6 +148,10 @@ const routeViewKey = computed(() =>
|
||||
route.path.startsWith('/settings') ? '/settings' : route.path
|
||||
)
|
||||
const searchQuery = ref('')
|
||||
// Starts false so the box is never drawn before the server has said the
|
||||
// caller can use it. A flash of a control that then vanishes reads worse than
|
||||
// one that arrives a moment late.
|
||||
const cansearch = ref(false)
|
||||
const navItems = ref([])
|
||||
const activeNotifications = ref([])
|
||||
const facilityName = ref('ShopDB')
|
||||
@@ -289,6 +296,15 @@ onMounted(async () => {
|
||||
navItems.value = buildNavItems(defaultNav)
|
||||
}
|
||||
|
||||
try {
|
||||
const caps = await dashboardApi.capabilities()
|
||||
cansearch.value = !!caps.data.data?.cansearch
|
||||
} catch (err) {
|
||||
// Leave the box hidden. Guessing from isAuthenticated here would put it
|
||||
// back in front of members who cannot search, which is the thing this
|
||||
// replaced.
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await notificationsApi.active()
|
||||
activeNotifications.value = resp.data.data?.notifications || []
|
||||
|
||||
Reference in New Issue
Block a user