refactor(stage-tamagotchi): improved about, better structure
This commit is contained in:
@@ -411,6 +411,9 @@ export function setupAutoUpdater(options: AutoUpdaterOptions = {}): AutoUpdater
|
||||
storedPreferredLane = lane
|
||||
options.setStoredUpdateLane?.(lane)
|
||||
resetPreparedFeedForLaneChange()
|
||||
// Keep UI state consistent with the newly selected lane.
|
||||
// A fresh check runs right after channel update from renderer.
|
||||
broadcast({ status: 'idle' })
|
||||
},
|
||||
subscribe(callback) {
|
||||
hooks.add(callback)
|
||||
|
||||
@@ -1,20 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import type { BugReportDialogSubmitPayload } from '@proj-airi/stage-ui/components'
|
||||
|
||||
import type { ElectronUpdaterChannel } from '../../shared/eventa'
|
||||
|
||||
import { useElectronAutoUpdater, useElectronEventaInvoke } from '@proj-airi/electron-vueuse'
|
||||
import { AboutContent, MarkdownRenderer } from '@proj-airi/stage-ui/components'
|
||||
import { AboutContent, BugReportDialog, createBugReportPageContext, MarkdownRenderer } from '@proj-airi/stage-ui/components'
|
||||
import { useBreakpoints } from '@proj-airi/stage-ui/composables'
|
||||
import { useSharedAnalyticsStore } from '@proj-airi/stage-ui/stores/analytics'
|
||||
import { Button, DoubleCheckButton, FieldSelect, Progress } from '@proj-airi/ui'
|
||||
import { Button, ContainerError, DoubleCheckButton, FieldSelect, Progress } from '@proj-airi/ui'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { DialogContent, DialogDescription, DialogOverlay, DialogPortal, DialogRoot, DialogTitle } from 'reka-ui'
|
||||
import { DrawerContent, DrawerDescription, DrawerHandle, DrawerOverlay, DrawerPortal, DrawerRoot, DrawerTitle } from 'vaul-vue'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
import { electronGetUpdaterPreferences, electronSetUpdaterPreferences } from '../../shared/eventa'
|
||||
|
||||
const analyticsStore = useSharedAnalyticsStore()
|
||||
const { buildInfo } = storeToRefs(analyticsStore)
|
||||
const { t } = useI18n()
|
||||
const { copy: copyToClipboard, isSupported: isClipboardSupported } = useClipboard()
|
||||
|
||||
const {
|
||||
state: updateState,
|
||||
@@ -29,23 +35,47 @@ const isLatestVersion = computed(() => {
|
||||
return updateState.value.status === 'not-available' && !isDisabled.value
|
||||
})
|
||||
const isError = computed(() => updateState.value.status === 'error')
|
||||
const updaterErrorMessage = computed(() => {
|
||||
const message = updateState.value.error?.message
|
||||
if (typeof message === 'string')
|
||||
return message
|
||||
|
||||
if (message == null)
|
||||
return ''
|
||||
|
||||
try {
|
||||
return JSON.stringify(message, null, 2)
|
||||
}
|
||||
catch {
|
||||
return String(message)
|
||||
}
|
||||
})
|
||||
|
||||
const links = [
|
||||
{ label: 'Home', href: 'https://airi.moeru.ai/docs/', icon: 'i-solar:home-smile-outline' },
|
||||
{ label: 'Documentations', href: 'https://airi.moeru.ai/docs/en/docs/overview/', icon: 'i-solar:document-add-outline' },
|
||||
{ label: 'GitHub', href: 'https://github.com/moeru-ai/airi', icon: 'i-simple-icons:github' },
|
||||
{ labelKey: 'tamagotchi.stage.about.links.home', href: 'https://airi.moeru.ai/docs/', icon: 'i-solar:home-smile-outline' },
|
||||
{ labelKey: 'tamagotchi.stage.about.links.documentation', href: 'https://airi.moeru.ai/docs/en/docs/overview/', icon: 'i-solar:document-add-outline' },
|
||||
{ labelKey: 'tamagotchi.stage.about.links.github', href: 'https://github.com/moeru-ai/airi', icon: 'i-simple-icons:github' },
|
||||
]
|
||||
|
||||
const showChangelog = ref(false)
|
||||
const showBugReportDialog = ref(false)
|
||||
const { isDesktop } = useBreakpoints()
|
||||
const updateChannelOptions = ['auto', 'stable', 'alpha', 'beta', 'nightly', 'canary'] as const
|
||||
const updateChannelSelectOptions = updateChannelOptions.map(channel => ({
|
||||
label: channel,
|
||||
const updateChannelSelectOptions = computed(() => updateChannelOptions.map(channel => ({
|
||||
label: t(`tamagotchi.stage.about.update.channels.${channel}`),
|
||||
value: channel,
|
||||
}))
|
||||
})))
|
||||
type UpdateChannelOption = typeof updateChannelOptions[number]
|
||||
const selectedUpdateChannel = ref<UpdateChannelOption>('auto')
|
||||
const isUpdateChannelUpdating = ref(false)
|
||||
const bugReportDescription = ref('')
|
||||
const includeBugReportTriageContext = ref(false)
|
||||
const uploadBugReportMediaFromLibrary = ref(false)
|
||||
const bugReportScreenshotFiles = ref<File[] | undefined>(undefined)
|
||||
const bugReportSending = ref(false)
|
||||
const bugReportSubmitError = ref<unknown>(undefined)
|
||||
const bugReportPageContext = ref(createBugReportPageContext())
|
||||
const bugReportScreenshotAttached = ref(false)
|
||||
|
||||
const isWindowsUpdater = computed(() => {
|
||||
return updateState.value.diagnostics?.platform === 'win32'
|
||||
@@ -53,13 +83,15 @@ const isWindowsUpdater = computed(() => {
|
||||
|
||||
const downloadedStatusText = computed(() => {
|
||||
if (isWindowsUpdater.value)
|
||||
return `Update ready to install silently (v${updateState.value.info?.version}).`
|
||||
return t('tamagotchi.stage.about.update.status.downloaded.windows', { version: updateState.value.info?.version ?? '' })
|
||||
|
||||
return `Update ready to install on restart (v${updateState.value.info?.version}).`
|
||||
return t('tamagotchi.stage.about.update.status.downloaded.restart', { version: updateState.value.info?.version ?? '' })
|
||||
})
|
||||
|
||||
const restartButtonLabel = computed(() => {
|
||||
return isWindowsUpdater.value ? 'Restart to update silently' : 'Restart to install update'
|
||||
return isWindowsUpdater.value
|
||||
? t('tamagotchi.stage.about.update.actions.restart-silent')
|
||||
: t('tamagotchi.stage.about.update.actions.restart-install')
|
||||
})
|
||||
|
||||
const getUpdaterPreferences = useElectronEventaInvoke(electronGetUpdaterPreferences)
|
||||
@@ -77,6 +109,45 @@ function confirmDownload() {
|
||||
downloadUpdate()
|
||||
}
|
||||
|
||||
function openBugReportDialog() {
|
||||
const details = [
|
||||
`Current version: ${buildInfo.value.version}`,
|
||||
`Update status: ${updateState.value.status}`,
|
||||
updaterErrorMessage.value ? `Error: ${updaterErrorMessage.value}` : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('\n')
|
||||
|
||||
bugReportDescription.value = details
|
||||
bugReportSubmitError.value = undefined
|
||||
showBugReportDialog.value = true
|
||||
}
|
||||
|
||||
function onBugReportRequestTriageContext() {
|
||||
includeBugReportTriageContext.value = true
|
||||
bugReportScreenshotAttached.value = true
|
||||
bugReportPageContext.value = createBugReportPageContext()
|
||||
}
|
||||
|
||||
async function onBugReportSubmit(payload: BugReportDialogSubmitPayload) {
|
||||
bugReportSending.value = true
|
||||
bugReportSubmitError.value = undefined
|
||||
|
||||
try {
|
||||
if (!isClipboardSupported.value)
|
||||
throw new Error('Clipboard API is unavailable')
|
||||
|
||||
await copyToClipboard(payload.formattedReport)
|
||||
showBugReportDialog.value = false
|
||||
}
|
||||
catch (error) {
|
||||
bugReportSubmitError.value = error
|
||||
}
|
||||
finally {
|
||||
bugReportSending.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshUpdaterChannelPreference() {
|
||||
const preferences = await getUpdaterPreferences()
|
||||
selectedUpdateChannel.value = preferences?.channel ?? 'auto'
|
||||
@@ -91,6 +162,7 @@ async function setUpdateChannelPreference(channel: UpdateChannelOption) {
|
||||
const nextChannel = channel === 'auto' ? undefined : channel as ElectronUpdaterChannel
|
||||
const preferences = await setUpdaterPreferences({ channel: nextChannel })
|
||||
selectedUpdateChannel.value = preferences?.channel ?? 'auto'
|
||||
await checkForUpdates()
|
||||
}
|
||||
finally {
|
||||
isUpdateChannelUpdating.value = false
|
||||
@@ -123,16 +195,20 @@ onMounted(() => {
|
||||
]"
|
||||
>
|
||||
<div :class="['mx-auto max-w-[min(960px,calc(100%-2rem))]', 'px-6 py-20']">
|
||||
<AboutContent title="Project" highlight="AIRI" subtitle="Desktop ver." />
|
||||
<AboutContent
|
||||
title="Project"
|
||||
highlight="AIRI"
|
||||
:subtitle="t('tamagotchi.stage.about.subtitle')"
|
||||
/>
|
||||
|
||||
<!-- Main Content Card -->
|
||||
<div :class="['mb-12', 'rounded-2xl', 'bg-white/50 dark:bg-black/20', 'p-6', 'backdrop-blur-sm']">
|
||||
<FieldSelect
|
||||
:model-value="selectedUpdateChannel"
|
||||
:disabled="isUpdateChannelUpdating"
|
||||
label="Update lane"
|
||||
description="Choose which release lane updater checks against. Auto follows the current app prerelease lane."
|
||||
placeholder="Choose update lane"
|
||||
:disabled="isUpdateChannelUpdating || isBusy"
|
||||
:label="t('tamagotchi.stage.about.update.lane.label')"
|
||||
:description="t('tamagotchi.stage.about.update.lane.description')"
|
||||
:placeholder="t('tamagotchi.stage.about.update.lane.placeholder')"
|
||||
:options="updateChannelSelectOptions"
|
||||
layout="vertical"
|
||||
:class="['mb-6']"
|
||||
@@ -143,7 +219,7 @@ onMounted(() => {
|
||||
<div :class="['flex flex-wrap items-center justify-between gap-4', 'mb-6', 'border-b border-neutral-200/50 dark:border-neutral-800/50', 'pb-6']">
|
||||
<div>
|
||||
<div :class="['text-sm text-neutral-500 dark:text-neutral-400']">
|
||||
Current Version
|
||||
{{ t('tamagotchi.stage.about.current-version') }}
|
||||
</div>
|
||||
<div :class="['text-xl font-medium font-mono']">
|
||||
{{ buildInfo.version }}
|
||||
@@ -169,7 +245,7 @@ onMounted(() => {
|
||||
variant="primary"
|
||||
:loading="isBusy"
|
||||
icon="i-solar:download-minimalistic-outline"
|
||||
label="Download Update"
|
||||
:label="t('tamagotchi.stage.about.update.actions.download')"
|
||||
@click="handleDownloadClick()"
|
||||
/>
|
||||
</div>
|
||||
@@ -178,7 +254,7 @@ onMounted(() => {
|
||||
<!-- State: Downloading -->
|
||||
<div v-else-if="updateState.status === 'downloading'" :class="['flex flex-col gap-2']">
|
||||
<div :class="['flex justify-between text-sm']">
|
||||
<span>Downloading update...</span>
|
||||
<span>{{ t('tamagotchi.stage.about.update.status.downloading') }}</span>
|
||||
<span :class="['font-mono']">{{ updateState.progress?.percent.toFixed(1) }}%</span>
|
||||
</div>
|
||||
<Progress :progress="updateState.progress?.percent ?? 0" />
|
||||
@@ -199,10 +275,10 @@ onMounted(() => {
|
||||
>
|
||||
{{ restartButtonLabel }}
|
||||
<template #confirm>
|
||||
Confirm Restart
|
||||
{{ t('tamagotchi.stage.about.update.actions.confirm-restart') }}
|
||||
</template>
|
||||
<template #cancel>
|
||||
Cancel
|
||||
{{ t('tamagotchi.stage.about.common.cancel') }}
|
||||
</template>
|
||||
</DoubleCheckButton>
|
||||
</div>
|
||||
@@ -210,11 +286,15 @@ onMounted(() => {
|
||||
|
||||
<!-- State: Idle, Checking, Error, Disabled, Not Available -->
|
||||
<div v-else :class="['flex flex-col gap-4']">
|
||||
<div v-if="isError" :class="['text-sm text-red-600 dark:text-red-400']">
|
||||
Error: {{ updateState.error?.message }}
|
||||
<div v-if="isError" :class="['flex flex-col gap-2']">
|
||||
<ContainerError
|
||||
:message="updaterErrorMessage"
|
||||
height-preset="sm"
|
||||
@feedback="openBugReportDialog"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="isLatestVersion" :class="['text-sm text-emerald-600 dark:text-emerald-400']">
|
||||
Up to date (v{{ buildInfo.version }}).
|
||||
{{ t('tamagotchi.stage.about.update.status.latest', { version: buildInfo.version }) }}
|
||||
</div>
|
||||
|
||||
<div :class="['flex flex-wrap gap-2']">
|
||||
@@ -223,7 +303,15 @@ onMounted(() => {
|
||||
:loading="isBusy"
|
||||
:disabled="isDisabled"
|
||||
:icon="isLatestVersion ? 'i-solar:check-circle-outline' : isDisabled ? 'i-solar:forbidden-circle-outline' : 'i-solar:refresh-outline'"
|
||||
:label="isBusy ? 'Checking...' : isLatestVersion ? 'Latest version' : isDisabled ? 'Updates disabled in Dev' : isError ? 'Retry Check' : 'Check for updates'"
|
||||
:label="isBusy
|
||||
? t('tamagotchi.stage.about.update.actions.checking')
|
||||
: isLatestVersion
|
||||
? t('tamagotchi.stage.about.update.actions.latest-version')
|
||||
: isDisabled
|
||||
? t('tamagotchi.stage.about.update.actions.disabled-dev')
|
||||
: isError
|
||||
? t('tamagotchi.stage.about.update.actions.retry-check')
|
||||
: t('tamagotchi.stage.about.update.actions.check-for-updates')"
|
||||
@click="checkForUpdates()"
|
||||
/>
|
||||
</div>
|
||||
@@ -234,7 +322,7 @@ onMounted(() => {
|
||||
<!-- Links -->
|
||||
<div>
|
||||
<div :class="['text-neutral-500 dark:text-neutral-400 mb-4']">
|
||||
Links
|
||||
{{ t('tamagotchi.stage.about.links.title') }}
|
||||
</div>
|
||||
<div :class="['flex flex-wrap gap-2']">
|
||||
<a
|
||||
@@ -247,7 +335,7 @@ onMounted(() => {
|
||||
<Button
|
||||
variant="secondary-muted"
|
||||
:icon="link.icon"
|
||||
:label="link.label"
|
||||
:label="t(link.labelKey)"
|
||||
size="sm"
|
||||
/>
|
||||
</a>
|
||||
@@ -261,22 +349,22 @@ onMounted(() => {
|
||||
<DialogOverlay class="fixed inset-0 z-[9999] bg-black/50 backdrop-blur-sm data-[state=closed]:animate-fadeOut data-[state=open]:animate-fadeIn" />
|
||||
<DialogContent class="fixed left-1/2 top-1/2 z-[9999] max-h-[85vh] max-w-2xl w-[90vw] flex flex-col rounded-2xl bg-white p-6 shadow-xl outline-none backdrop-blur-md -translate-x-1/2 -translate-y-1/2 data-[state=closed]:animate-contentHide data-[state=open]:animate-contentShow dark:bg-neutral-900">
|
||||
<DialogTitle class="mb-2 text-lg font-medium">
|
||||
Update Available
|
||||
{{ t('tamagotchi.stage.about.update.dialog.title') }}
|
||||
</DialogTitle>
|
||||
<DialogDescription class="mb-4 text-sm text-neutral-500 dark:text-neutral-400">
|
||||
A new version (v{{ updateState.info?.version }}) is available.
|
||||
{{ t('tamagotchi.stage.about.update.dialog.description', { version: updateState.info?.version }) }}
|
||||
</DialogDescription>
|
||||
|
||||
<div class="min-h-0 flex-1 overflow-y-auto border border-neutral-200 rounded-lg bg-neutral-50 p-4 dark:border-neutral-800 dark:bg-neutral-950/50">
|
||||
<MarkdownRenderer :content="releaseNotesContent || '_No release notes provided._'" class="text-sm" />
|
||||
<MarkdownRenderer :content="releaseNotesContent || t('tamagotchi.stage.about.update.dialog.no-release-notes-markdown')" class="text-sm" />
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-end gap-3">
|
||||
<Button variant="secondary" @click="showChangelog = false">
|
||||
Cancel
|
||||
{{ t('tamagotchi.stage.about.common.cancel') }}
|
||||
</Button>
|
||||
<Button variant="primary" icon="i-solar:download-minimalistic-outline" @click="confirmDownload">
|
||||
Confirm Download
|
||||
{{ t('tamagotchi.stage.about.update.actions.confirm-download') }}
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
@@ -291,28 +379,42 @@ onMounted(() => {
|
||||
<div class="flex flex-1 flex-col rounded-t-2xl bg-white p-4 dark:bg-neutral-900">
|
||||
<DrawerHandle class="mx-auto mb-4 h-1.5 w-12 rounded-full bg-neutral-300 dark:bg-neutral-700" />
|
||||
<DrawerTitle class="mb-2 text-lg font-medium">
|
||||
Update Available
|
||||
{{ t('tamagotchi.stage.about.update.dialog.title') }}
|
||||
</DrawerTitle>
|
||||
<DrawerDescription class="mb-4 text-sm text-neutral-500 dark:text-neutral-400">
|
||||
A new version (v{{ updateState.info?.version }}) is available.
|
||||
{{ t('tamagotchi.stage.about.update.dialog.description', { version: updateState.info?.version }) }}
|
||||
</DrawerDescription>
|
||||
|
||||
<div class="min-h-0 flex-1 overflow-y-auto border border-neutral-200 rounded-lg bg-neutral-50 p-4 dark:border-neutral-800 dark:bg-neutral-950/50">
|
||||
<MarkdownRenderer :content="releaseNotesContent || '_No release notes provided._'" class="text-sm" />
|
||||
<MarkdownRenderer :content="releaseNotesContent || t('tamagotchi.stage.about.update.dialog.no-release-notes-markdown')" class="text-sm" />
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex gap-3">
|
||||
<Button variant="secondary" block @click="showChangelog = false">
|
||||
Cancel
|
||||
{{ t('tamagotchi.stage.about.common.cancel') }}
|
||||
</Button>
|
||||
<Button variant="primary" block icon="i-solar:download-minimalistic-outline" @click="confirmDownload">
|
||||
Download
|
||||
{{ t('tamagotchi.stage.about.update.actions.download-short') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</DrawerContent>
|
||||
</DrawerPortal>
|
||||
</DrawerRoot>
|
||||
|
||||
<BugReportDialog
|
||||
v-model="showBugReportDialog"
|
||||
v-model:description="bugReportDescription"
|
||||
v-model:include-triage-context="includeBugReportTriageContext"
|
||||
v-model:upload-media-from-library="uploadBugReportMediaFromLibrary"
|
||||
v-model:screenshot-files="bugReportScreenshotFiles"
|
||||
:sending="bugReportSending"
|
||||
:submit-error="bugReportSubmitError"
|
||||
:page-context="bugReportPageContext"
|
||||
:screenshot-attached="bugReportScreenshotAttached"
|
||||
@request-triage-context="onBugReportRequestTriageContext"
|
||||
@submit="onBugReportSubmit"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import { useElectronAutoUpdater } from '@proj-airi/electron-vueuse'
|
||||
import { useSettings } from '@proj-airi/stage-ui/stores/settings'
|
||||
import { Button, Progress } from '@proj-airi/ui'
|
||||
import { computed } from 'vue'
|
||||
|
||||
const settings = useSettings()
|
||||
|
||||
const {
|
||||
state: updateState,
|
||||
isBusy,
|
||||
@@ -36,74 +33,69 @@ const diagnosticsEntries = computed(() => {
|
||||
|
||||
<template>
|
||||
<div :class="['flex flex-col gap-4', 'pb-8']">
|
||||
<div
|
||||
v-if="!settings.inspectUpdaterDiagnostics"
|
||||
:class="['rounded-2xl border border-amber-500/30 bg-amber-500/10 p-4 text-sm text-amber-100']"
|
||||
>
|
||||
Enable "Inspect updater diagnostics" from Settings > System > Developer to inspect updater internals here.
|
||||
<div :class="['flex flex-wrap gap-2']">
|
||||
<Button
|
||||
variant="secondary"
|
||||
:loading="isBusy"
|
||||
icon="i-solar:refresh-outline"
|
||||
label="Check for updates"
|
||||
@click="checkForUpdates()"
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
:disabled="updateState.status !== 'available'"
|
||||
icon="i-solar:download-minimalistic-outline"
|
||||
label="Download update"
|
||||
@click="downloadUpdate()"
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
:disabled="updateState.status !== 'downloaded'"
|
||||
icon="i-solar:restart-bold-duotone"
|
||||
label="Restart to install"
|
||||
@click="quitAndInstall()"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<div :class="['flex flex-wrap gap-2']">
|
||||
<Button
|
||||
variant="secondary"
|
||||
:loading="isBusy"
|
||||
icon="i-solar:refresh-outline"
|
||||
label="Check for updates"
|
||||
@click="checkForUpdates()"
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
:disabled="updateState.status !== 'available'"
|
||||
icon="i-solar:download-minimalistic-outline"
|
||||
label="Download update"
|
||||
@click="downloadUpdate()"
|
||||
/>
|
||||
<Button
|
||||
variant="secondary"
|
||||
:disabled="updateState.status !== 'downloaded'"
|
||||
icon="i-solar:restart-bold-duotone"
|
||||
label="Restart to install"
|
||||
@click="quitAndInstall()"
|
||||
/>
|
||||
<div v-if="updateState.status === 'downloading'" :class="['flex flex-col gap-2']">
|
||||
<div :class="['flex items-center justify-between text-sm text-neutral-600 dark:text-neutral-300']">
|
||||
<span>Downloading update</span>
|
||||
<span>{{ updateState.progress?.percent.toFixed(1) }}%</span>
|
||||
</div>
|
||||
<Progress :progress="updateState.progress?.percent ?? 0" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="updateState.status === 'error'"
|
||||
:class="[
|
||||
'rounded-2xl border-2 p-4 text-sm whitespace-pre-wrap',
|
||||
'border-red-300/60 bg-red-50 text-red-700',
|
||||
'dark:border-red-500/30 dark:bg-red-500/10 dark:text-red-100',
|
||||
]"
|
||||
>
|
||||
{{ updateState.error?.message }}
|
||||
</div>
|
||||
|
||||
<section :class="['rounded-2xl border-2 p-4', 'border-neutral-200 bg-white/70 dark:border-neutral-700/60 dark:bg-neutral-950/40']">
|
||||
<div :class="['mb-3 text-sm text-neutral-600 dark:text-neutral-400']">
|
||||
Updater diagnostics
|
||||
</div>
|
||||
|
||||
<div v-if="updateState.status === 'downloading'" :class="['flex flex-col gap-2']">
|
||||
<div :class="['flex items-center justify-between text-sm text-neutral-300']">
|
||||
<span>Downloading update</span>
|
||||
<span>{{ updateState.progress?.percent.toFixed(1) }}%</span>
|
||||
</div>
|
||||
<Progress :progress="updateState.progress?.percent ?? 0" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="updateState.status === 'error'"
|
||||
:class="['rounded-2xl border border-red-500/30 bg-red-500/10 p-4 text-sm text-red-100 whitespace-pre-wrap']"
|
||||
>
|
||||
{{ updateState.error?.message }}
|
||||
</div>
|
||||
|
||||
<section :class="['rounded-2xl border border-neutral-700/60', 'bg-neutral-950/40 p-4']">
|
||||
<div :class="['mb-3 text-sm text-neutral-400']">
|
||||
Updater diagnostics
|
||||
</div>
|
||||
|
||||
<div :class="['grid gap-2 text-sm text-neutral-100']">
|
||||
<div
|
||||
v-for="[label, value] in diagnosticsEntries"
|
||||
:key="label"
|
||||
:class="['grid gap-1 md:grid-cols-[180px_minmax(0,1fr)]']"
|
||||
>
|
||||
<div :class="['text-neutral-400']">
|
||||
{{ label }}
|
||||
</div>
|
||||
<div :class="['font-mono break-words']">
|
||||
{{ value }}
|
||||
</div>
|
||||
<div :class="['grid gap-2 text-sm text-neutral-800 dark:text-neutral-100']">
|
||||
<div
|
||||
v-for="[label, value] in diagnosticsEntries"
|
||||
:key="label"
|
||||
:class="['grid gap-1 md:grid-cols-[180px_minmax(0,1fr)]']"
|
||||
>
|
||||
<div :class="['text-neutral-500 dark:text-neutral-400']">
|
||||
{{ label }}
|
||||
</div>
|
||||
<div :class="['font-mono break-words']">
|
||||
{{ value }}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -143,16 +143,6 @@ const openDevtoolsWindow = useElectronEventaInvoke(electronOpenDevtoolsWindow)
|
||||
description="settings.animations.use-page-specific-transitions.description"
|
||||
transition="all ease-in-out duration-250"
|
||||
/>
|
||||
<CheckBar
|
||||
v-model="settings.inspectUpdaterDiagnostics"
|
||||
mb-2
|
||||
icon-on="i-solar:bug-bold-duotone"
|
||||
icon-off="i-solar:bug-minimalistic-outline"
|
||||
text="Inspect updater diagnostics"
|
||||
description="Show detailed updater diagnostics in the developer updater page."
|
||||
transition="all ease-in-out duration-250"
|
||||
/>
|
||||
|
||||
<div flex="~ col gap-4" mt-2 pb-12>
|
||||
<IconItem
|
||||
v-for="(item, index) in menu"
|
||||
|
||||
Reference in New Issue
Block a user