Bound federated sync and show progress feedback
This commit is contained in:
@@ -62,6 +62,7 @@
|
||||
:invite-type="inviteType"
|
||||
:invite-code="inviteCode"
|
||||
:syncing="syncing"
|
||||
:sync-node-count="syncableNodeCount"
|
||||
@generate-invite="handleGenerateInvite"
|
||||
@show-join="showJoinModal = true"
|
||||
@sync="syncAll"
|
||||
@@ -311,6 +312,7 @@ const joinSuccess = ref(false)
|
||||
|
||||
const syncing = ref(false)
|
||||
const syncResults = ref<SyncResult[]>([])
|
||||
const syncableNodeCount = computed(() => nodes.value.filter(node => node.trust_level !== 'untrusted').length)
|
||||
|
||||
const deploying = ref(false)
|
||||
const deployResult = ref('')
|
||||
|
||||
@@ -74,11 +74,16 @@
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
data-testid="federation-sync-button"
|
||||
@click="$emit('sync')"
|
||||
class="w-full sm:w-fit px-3 py-1.5 glass-button glass-button-sm rounded text-xs font-medium text-white/90 hover:text-white transition-colors disabled:opacity-50"
|
||||
:disabled="syncing"
|
||||
>
|
||||
{{ syncing ? 'Syncing...' : 'Sync Now' }}
|
||||
<span v-if="syncing" class="inline-flex items-center gap-2" role="status" aria-live="polite">
|
||||
<span class="w-3 h-3 border-2 border-white/30 border-t-white rounded-full animate-spin" aria-hidden="true"></span>
|
||||
Syncing {{ syncNodeCount }} node{{ syncNodeCount === 1 ? '' : 's' }}…
|
||||
</span>
|
||||
<span v-else>Sync Now</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,6 +126,7 @@ const props = defineProps<{
|
||||
inviteType: 'trusted' | 'observer'
|
||||
inviteCode: string
|
||||
syncing: boolean
|
||||
syncNodeCount: number
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import QuickActions from '../QuickActions.vue'
|
||||
|
||||
describe('QuickActions federation sync', () => {
|
||||
it('shows bounded progress context while sync is running', () => {
|
||||
const wrapper = mount(QuickActions, {
|
||||
props: {
|
||||
generatingInvite: false,
|
||||
inviteType: 'trusted',
|
||||
inviteCode: '',
|
||||
syncing: true,
|
||||
syncNodeCount: 3,
|
||||
},
|
||||
})
|
||||
|
||||
const button = wrapper.get('[data-testid="federation-sync-button"]')
|
||||
expect(button.attributes('disabled')).toBeDefined()
|
||||
const status = button.get('[role="status"]')
|
||||
expect(status.attributes('aria-live')).toBe('polite')
|
||||
expect(status.text()).toContain('Syncing 3 nodes')
|
||||
expect(status.find('.animate-spin').exists()).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps the action concise for a single node', () => {
|
||||
const wrapper = mount(QuickActions, {
|
||||
props: {
|
||||
generatingInvite: false,
|
||||
inviteType: 'trusted',
|
||||
inviteCode: '',
|
||||
syncing: true,
|
||||
syncNodeCount: 1,
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.get('[data-testid="federation-sync-button"]').text()).toContain('Syncing 1 node…')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user