diff --git a/neode-ui/src/views/Credentials.vue b/neode-ui/src/views/Credentials.vue index d50f7f92..84130045 100644 --- a/neode-ui/src/views/Credentials.vue +++ b/neode-ui/src/views/Credentials.vue @@ -199,8 +199,9 @@ diff --git a/neode-ui/src/views/__tests__/CredentialsRefresh.test.ts b/neode-ui/src/views/__tests__/CredentialsRefresh.test.ts index 903d0fc2..a2b7aabc 100644 --- a/neode-ui/src/views/__tests__/CredentialsRefresh.test.ts +++ b/neode-ui/src/views/__tests__/CredentialsRefresh.test.ts @@ -1,5 +1,6 @@ import { flushPromises, mount } from '@vue/test-utils' import { describe, expect, it, vi } from 'vitest' +import { createPinia } from 'pinia' import Credentials from '../Credentials.vue' import { rpcClient } from '@/api/rpc-client' @@ -42,6 +43,8 @@ describe('Credentials', () => { const wrapper = mount(Credentials, { global: { + // The cached-resource layer pulls the Pinia resources store in setup. + plugins: [createPinia()], mocks: { $router: { push: vi.fn() }, }, diff --git a/neode-ui/src/views/server/OpenWrtGateway.vue b/neode-ui/src/views/server/OpenWrtGateway.vue index 1b091056..c959096e 100644 --- a/neode-ui/src/views/server/OpenWrtGateway.vue +++ b/neode-ui/src/views/server/OpenWrtGateway.vue @@ -2,6 +2,7 @@ import { ref, computed, onMounted } from 'vue' import { useRouter } from 'vue-router' import { rpcClient } from '@/api/rpc-client' +import { useResourcesStore } from '@/stores/resources' import BackButton from '@/components/BackButton.vue' const router = useRouter() @@ -73,8 +74,15 @@ interface ScannedNetwork { encryption: string } -const status = ref(null) -const loading = ref(true) +const status = computed(() => statusEntry().data) +// Router status is cached in the shared resources store so revisits paint +// the last-known state instantly while a fresh read runs behind it. +const resources = useResourcesStore() +const statusEntry = () => resources.entry('server.openwrt-status') +const loading = computed(() => { + const s = statusEntry().loadState + return s === 'loading' || s === 'refreshing' || (s === 'idle' && statusEntry().data === null) +}) const error = ref('') const host = ref('') const sshUser = ref('root') @@ -115,25 +123,25 @@ const dhcpLimit = ref(150) const masqEnabled = ref(true) async function load(params?: Record) { - loading.value = true error.value = '' - try { - status.value = await rpcClient.call({ + await resources.refresh('server.openwrt-status', () => + rpcClient.call({ method: 'openwrt.get-status', params: params ?? {}, timeout: 30000, - }) - showConnectForm.value = false - if (params) connectedParams.value = params - } catch (e) { - const msg = e instanceof Error ? e.message : String(e) - if (msg.includes('No router configured')) { + dedup: true, + maxRetries: 1, + })) + const err = statusEntry().error + if (err) { + if (err.includes('No router configured')) { showConnectForm.value = true } else { - error.value = msg + error.value = err } - } finally { - loading.value = false + } else { + showConnectForm.value = false + if (params) connectedParams.value = params } }