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:
co-authored by
Claude Opus 4.6
parent
5ce8b7965c
commit
e3aa95a103
@@ -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) */
|
||||
|
||||
Reference in New Issue
Block a user