fix: prevent tokio runtime deadlock in credential issue/verify

The credential issuance and verification handlers used
Handle::block_on() directly inside the tokio runtime, causing a
deadlock. Wrapped with block_in_place() to properly yield the
runtime thread.

Also completed full feature verification across all 25 test groups
(~175 checks) on live server.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-09 07:43:12 +00:00
co-authored by Claude Opus 4.6
parent 5ce8b7965c
commit e3aa95a103
81 changed files with 11492 additions and 649 deletions
+23 -6
View File
@@ -94,6 +94,10 @@
/>
</svg>
<span>{{ item.label }}</span>
<span
v-if="item.path === '/dashboard/web5' && web5Badge.pendingRequestCount > 0"
class="ml-auto w-5 h-5 flex items-center justify-center rounded-full bg-orange-500 text-white text-[10px] font-bold"
>{{ web5Badge.pendingRequestCount }}</span>
</RouterLink>
<!-- Chat launcher button -->
@@ -298,7 +302,7 @@
v-for="item in mobileNavItems"
:key="item.path"
:to="item.path"
class="flex items-center justify-center w-full py-3 rounded-lg text-white/70 transition-all duration-300 relative z-10"
class="flex flex-col items-center justify-center w-full py-1.5 rounded-lg text-white/70 transition-all duration-300 relative z-10 gap-0.5"
:class="{
'nav-tab-active': item.isCombined
? (item.path === '/dashboard/apps'
@@ -308,7 +312,7 @@
}"
:exact-active-class="item.isCombined ? undefined : 'nav-tab-active'"
>
<svg class="w-7 h-7 transition-all duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-6 h-6 transition-all duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path
v-for="(path, index) in getIconPath(item.icon)"
:key="index"
@@ -318,15 +322,17 @@
:d="path"
/>
</svg>
<span class="text-[10px] leading-tight">{{ item.label }}</span>
</RouterLink>
<!-- Chat launcher -->
<button
@click="router.push('/dashboard/chat')"
class="chat-launcher-btn-mobile flex items-center justify-center w-full py-3 rounded-lg transition-all duration-300 relative z-10"
class="chat-launcher-btn-mobile flex flex-col items-center justify-center w-full py-1.5 rounded-lg transition-all duration-300 relative z-10 gap-0.5"
>
<svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path v-for="(path, index) in getIconPath('chat')" :key="index" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" :d="path" />
</svg>
<span class="text-[10px] leading-tight">Chat</span>
</button>
</div>
</nav>
@@ -344,6 +350,7 @@ import ControllerIndicator from '@/components/ControllerIndicator.vue'
import ModeSwitcher from '@/components/ModeSwitcher.vue'
import { useUIModeStore } from '@/stores/uiMode'
import { playDashboardLoadOomph } from '@/composables/useLoginSounds'
import { useWeb5BadgeStore } from '@/stores/web5Badge'
const uiMode = useUIModeStore()
@@ -355,6 +362,7 @@ const router = useRouter()
const route = useRoute()
const store = useAppStore()
const loginTransition = useLoginTransitionStore()
const web5Badge = useWeb5BadgeStore()
const showZoomIn = ref(false)
const pendingTimers: ReturnType<typeof setTimeout>[] = []
@@ -537,6 +545,7 @@ onMounted(() => {
onResize()
window.addEventListener('resize', onResize)
web5Badge.refresh()
})
onBeforeUnmount(() => {
@@ -1329,45 +1338,53 @@ aside:not(.sidebar-animate) .sidebar-logout-btn {
/* Mobile: Slide left transition (Apps -> Marketplace) */
.slide-left-enter-active.view-wrapper,
.slide-left-leave-active.view-wrapper {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}
.slide-left-enter-from.view-wrapper {
transform: translateX(100%);
opacity: 0;
}
.slide-left-enter-to.view-wrapper {
transform: translateX(0);
opacity: 1;
}
.slide-left-leave-from.view-wrapper {
transform: translateX(0);
opacity: 1;
}
.slide-left-leave-to.view-wrapper {
transform: translateX(-100%);
opacity: 0;
}
/* Mobile: Slide right transition (Marketplace -> Apps) */
.slide-right-enter-active.view-wrapper,
.slide-right-leave-active.view-wrapper {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
}
.slide-right-enter-from.view-wrapper {
transform: translateX(-100%);
opacity: 0;
}
.slide-right-enter-to.view-wrapper {
transform: translateX(0);
opacity: 1;
}
.slide-right-leave-from.view-wrapper {
transform: translateX(0);
opacity: 1;
}
.slide-right-leave-to.view-wrapper {
transform: translateX(100%);
opacity: 0;
}
/* Slide down: Moving down the menu (content slides up like a scroll) */