refac: revamp the update flow in settings so the user has better visibility that it has to restart when update downloaded
This commit is contained in:
1 parent
daf497576f
commit
68401d66e0
9 files changed
+70
-16
No files matched your search
@@ -17,6 +17,7 @@ const props = defineProps<{
|
||||
title: string
|
||||
text: string
|
||||
meta?: string
|
||||
tag?: string
|
||||
live?: 'polite' | 'off'
|
||||
}>()
|
||||
|
||||
@@ -37,10 +38,21 @@ const spinning = computed(() => props.icon === 'i-lucide-loader-circle')
|
||||
/>
|
||||
</span>
|
||||
<div class="flex min-w-0 flex-1 flex-col gap-1">
|
||||
<span class="text-base font-semibold text-highlighted">{{ title }}</span>
|
||||
<div class="flex flex-wrap items-center gap-2">
|
||||
<span class="text-base font-semibold text-highlighted">{{ title }}</span>
|
||||
<span
|
||||
v-if="tag"
|
||||
data-testid="update-tag"
|
||||
class="inline-flex h-5 items-center border border-warning bg-default px-1.5 font-mono text-[0.6875rem] font-medium text-warning"
|
||||
>{{ tag }}</span
|
||||
>
|
||||
</div>
|
||||
<span class="text-sm text-pretty text-toned">{{ text }}</span>
|
||||
<slot />
|
||||
<span v-if="meta" class="text-xs/5 text-muted">{{ meta }}</span>
|
||||
<div v-if="$slots.action" class="flex pt-2">
|
||||
<slot name="action" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -39,6 +39,7 @@ interface Block {
|
||||
title: string
|
||||
text: string
|
||||
meta?: string
|
||||
tag?: string
|
||||
}
|
||||
|
||||
interface ActionButton {
|
||||
@@ -187,8 +188,11 @@ const applyBlocks = computed<Record<ApplyView, Block>>(() => ({
|
||||
},
|
||||
},
|
||||
ready: {
|
||||
tone: 'success',
|
||||
icon: 'i-lucide-circle-check',
|
||||
tone: 'warning',
|
||||
icon: 'i-lucide-clock',
|
||||
get tag() {
|
||||
return t('Pending')
|
||||
},
|
||||
get title() {
|
||||
return t('Version {0} is ready to install', [newVersion.value])
|
||||
},
|
||||
@@ -498,6 +502,12 @@ const actionButtons = computed<ActionButton[]>(() => {
|
||||
})
|
||||
})
|
||||
|
||||
const inBlockButton = computed(() =>
|
||||
applyView.value === 'ready' ? (actionButtons.value[0] ?? null) : null,
|
||||
)
|
||||
|
||||
const rowButtons = computed(() => (inBlockButton.value ? [] : actionButtons.value))
|
||||
|
||||
const showRestartHint = computed(() => actionButtons.value.includes(plainRestartButton))
|
||||
|
||||
function withPlainRestart(button: ActionButton) {
|
||||
@@ -577,6 +587,7 @@ const notes = computed(() => {
|
||||
:title="block.title"
|
||||
:text="block.text"
|
||||
:meta="block.meta"
|
||||
:tag="block.tag"
|
||||
:live="progressView ? 'off' : 'polite'"
|
||||
>
|
||||
<UpdateProgress
|
||||
@@ -585,6 +596,25 @@ const notes = computed(() => {
|
||||
:text="progressView.text"
|
||||
:value="progressView.value"
|
||||
/>
|
||||
<template v-if="inBlockButton" #action>
|
||||
<UButton
|
||||
:data-testid="inBlockButton.action === 'restart' ? 'restart-button' : undefined"
|
||||
:color="inBlockButton.primary ? 'primary' : 'neutral'"
|
||||
:variant="inBlockButton.primary ? 'solid' : 'outline'"
|
||||
:icon="inBlockButton.icon"
|
||||
:disabled="inBlockButton.disabled"
|
||||
class="h-11 justify-center gap-1.5 px-3.5 md:h-8"
|
||||
:class="
|
||||
inBlockButton.primary
|
||||
? ''
|
||||
: 'border border-accented bg-default text-highlighted ring-0'
|
||||
"
|
||||
:ui="{ leadingIcon: 'size-4' }"
|
||||
@click="onAction(inBlockButton)"
|
||||
>
|
||||
{{ inBlockButton.label }}
|
||||
</UButton>
|
||||
</template>
|
||||
</UpdateStatusBlock>
|
||||
|
||||
<p v-if="canApplyView" role="status" data-testid="update-announcer" class="sr-only">
|
||||
@@ -595,9 +625,9 @@ const notes = computed(() => {
|
||||
|
||||
<ServerCommand v-if="showServerGuidance" :line="ENABLE_BROWSER_UPDATES_COMMAND" />
|
||||
|
||||
<div v-if="actionButtons.length" class="flex flex-col gap-2 md:flex-row md:items-center">
|
||||
<div v-if="rowButtons.length" class="flex flex-col gap-2 md:flex-row md:items-center">
|
||||
<UButton
|
||||
v-for="button in actionButtons"
|
||||
v-for="button in rowButtons"
|
||||
:key="button.label"
|
||||
:data-testid="button.action === 'restart' ? 'restart-button' : undefined"
|
||||
:color="button.primary ? 'primary' : 'neutral'"
|
||||
|
||||
@@ -299,7 +299,7 @@ describe('Settings, owner, Restart buttons', () => {
|
||||
it('ready: Restart is the enabled primary button', async () => {
|
||||
await mountSettings({ role: 'owner', status: ready() })
|
||||
|
||||
expect(cardButtons()).toEqual(["What's new in 2.3.0-beta", 'Restart'])
|
||||
expect(cardButtons()).toEqual(['Restart', "What's new in 2.3.0-beta"])
|
||||
const restart = findButton('Restart') as HTMLButtonElement
|
||||
expect(restart.disabled).toBe(false)
|
||||
expect(restart.className).not.toContain('border-accented')
|
||||
|
||||
@@ -311,6 +311,16 @@ describe('Settings, owner, Ready to install', () => {
|
||||
expect(findButton("What's new in 2.3.0-beta")!.getAttribute('aria-expanded')).toBe('false')
|
||||
const restart = findButton('Restart') as HTMLButtonElement
|
||||
expect(restart.disabled).toBe(false)
|
||||
const tag = updatesCard().querySelector('[data-testid="update-tag"]')
|
||||
expect(tag?.textContent?.trim()).toBe('Pending')
|
||||
expect(updatesCard().querySelector('svg.text-warning')).not.toBeNull()
|
||||
expect(updatesCard().querySelector('svg.text-success')).toBeNull()
|
||||
const block = updatesCard().querySelector('[aria-live]') as HTMLElement
|
||||
expect(block.className).toContain('--rc-warning-soft')
|
||||
expect(block.contains(restart)).toBe(true)
|
||||
expect(restart.className).toContain('h-11')
|
||||
expect(restart.className).toContain('md:h-8')
|
||||
expect(updatesCard().querySelector('[class*="md:flex-row"]')).toBeNull()
|
||||
|
||||
const readsBefore = callsTo(STATUS_PATH).length
|
||||
await tick(3000)
|
||||
|
||||
Reference in new issue
Block a user