fix: prerelease fixes (#5793)

This commit is contained in:
Calum H.
2026-04-13 01:58:50 +02:00
committed by GitHub
parent 0b8b4fb516
commit 0713814d0c
6 changed files with 178 additions and 112 deletions

View File

@@ -2,6 +2,7 @@
import { injectModrinthServerContext, ServersManageOverviewPage } from '@modrinth/ui' import { injectModrinthServerContext, ServersManageOverviewPage } from '@modrinth/ui'
const { server } = injectModrinthServerContext() const { server } = injectModrinthServerContext()
const flags = useFeatureFlags()
useHead({ useHead({
title: computed(() => `Overview - ${server.value?.name ?? 'Server'} - Modrinth`), title: computed(() => `Overview - ${server.value?.name ?? 'Server'} - Modrinth`),
@@ -9,5 +10,5 @@ useHead({
</script> </script>
<template> <template>
<ServersManageOverviewPage /> <ServersManageOverviewPage :show-advanced-debug-info="flags.advancedDebugInfo" />
</template> </template>

View File

@@ -1,4 +1,5 @@
<template> <template>
<Teleport to="body">
<div <div
v-if="open" v-if="open"
:style="`${mouseX !== -1 ? `--_mouse-x: ${mouseX};` : ''} ${mouseY !== -1 ? `--_mouse-y: ${mouseY};` : ''}`" :style="`${mouseX !== -1 ? `--_mouse-x: ${mouseX};` : ''} ${mouseY !== -1 ? `--_mouse-y: ${mouseY};` : ''}`"
@@ -134,6 +135,7 @@
</div> </div>
</div> </div>
</div> </div>
</Teleport>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">

View File

@@ -23,7 +23,6 @@ export function useServerPowerAction(options?: { disabled?: Ref<boolean> }) {
const showStopButton = computed(() => isRunning.value || isStarting.value) const showStopButton = computed(() => isRunning.value || isStarting.value)
const busyTooltip = computed(() => { const busyTooltip = computed(() => {
if (isStopping.value) return 'Server is currently stopping'
if (isStarting.value) return 'Your server is starting' if (isStarting.value) return 'Your server is starting'
return busyReasons.value.length > 0 ? formatMessage(busyReasons.value[0].reason) : undefined return busyReasons.value.length > 0 ? formatMessage(busyReasons.value[0].reason) : undefined
}) })
@@ -37,6 +36,8 @@ export function useServerPowerAction(options?: { disabled?: Ref<boolean> }) {
case 'running': case 'running':
case 'starting': case 'starting':
return 'Restart' return 'Restart'
case 'stopping':
return 'Stopping'
default: default:
return 'Start' return 'Start'
} }

View File

@@ -194,16 +194,16 @@ function formatLog4jLines(event: Log4jEvent): LogLine[] {
const message = event.message?.trim() ?? '' const message = event.message?.trim() ?? ''
const prefix = time ? `${time} [${thread}/${levelStr}]: ` : `[${thread}/${levelStr}]: ` const prefix = time ? `${time} [${thread}/${levelStr}]: ` : `[${thread}/${levelStr}]: `
const messageLines = message.split(/\r?\n/) const messageLines = message.split(/[\r\n]+/)
const lines: LogLine[] = [{ text: prefix + messageLines[0], level }] const lines: LogLine[] = [{ text: prefix + messageLines[0], level }]
for (let i = 1; i < messageLines.length; i++) { for (let i = 1; i < messageLines.length; i++) {
if (!messageLines[i].trim()) continue if (!messageLines[i]) continue
lines.push({ text: messageLines[i], level }) lines.push({ text: messageLines[i], level })
} }
if (event.throwable) { if (event.throwable) {
for (const line of event.throwable.split(/\r?\n/)) { for (const line of event.throwable.split(/[\r\n]+/)) {
if (!line.trim()) continue if (!line) continue
lines.push({ text: line, level: 'error' }) lines.push({ text: line, level: 'error' })
} }
} }
@@ -218,6 +218,9 @@ function textToLogLine(text: string): LogLine {
export function createConsoleState() { export function createConsoleState() {
const archive = new ColumnarRingBuffer(ARCHIVE_CAPACITY) const archive = new ColumnarRingBuffer(ARCHIVE_CAPACITY)
const output: Ref<LogLine[]> = shallowRef<LogLine[]>([]) const output: Ref<LogLine[]> = shallowRef<LogLine[]>([])
const WS_EVENT_HISTORY_MAX = 25000
const wsEventHistory: unknown[] = []
let wsEventCaptureEnabled = false
let lineBuffer: LogLine[] = [] let lineBuffer: LogLine[] = []
let batchTimer: NodeJS.Timeout | null = null let batchTimer: NodeJS.Timeout | null = null
@@ -283,10 +286,25 @@ export function createConsoleState() {
addLines(formatLog4jLines(event)) addLines(formatLog4jLines(event))
} }
const recordWsEvent = (event: unknown): void => {
if (!wsEventCaptureEnabled) return
wsEventHistory.push(event)
if (wsEventHistory.length > WS_EVENT_HISTORY_MAX) {
wsEventHistory.splice(0, wsEventHistory.length - WS_EVENT_HISTORY_MAX)
}
}
const getWsEventHistory = (): unknown[] => wsEventHistory.slice()
const setWsEventCaptureEnabled = (enabled: boolean): void => {
wsEventCaptureEnabled = enabled
if (!enabled) wsEventHistory.length = 0
}
const addLegacyLog = (message: string): void => { const addLegacyLog = (message: string): void => {
const logLines = message const logLines = message
.split('\n') .split(/[\r\n]+/)
.filter((l) => l.trim()) .filter((l) => l)
.map(textToLogLine) .map(textToLogLine)
let parentLevel: LogLevel | null = null let parentLevel: LogLevel | null = null
@@ -306,6 +324,7 @@ export function createConsoleState() {
archive.clear() archive.clear()
output.value = [] output.value = []
lineBuffer = [] lineBuffer = []
wsEventHistory.length = 0
wrapCount = 0 wrapCount = 0
if (batchTimer) { if (batchTimer) {
clearTimeout(batchTimer) clearTimeout(batchTimer)
@@ -343,6 +362,9 @@ export function createConsoleState() {
addLines, addLines,
addLog4jEvent, addLog4jEvent,
addLegacyLog, addLegacyLog,
recordWsEvent,
getWsEventHistory,
setWsEventCaptureEnabled,
clear, clear,
__debugStats, __debugStats,
} }

View File

@@ -198,11 +198,13 @@ export function useServerManageCoreRuntime(options: UseServerManageCoreRuntimeOp
const handleLog = (data: Archon.Websocket.v0.WSLogEvent) => { const handleLog = (data: Archon.Websocket.v0.WSLogEvent) => {
if (!shouldProcessEvent()) return if (!shouldProcessEvent()) return
modrinthServersConsole.recordWsEvent({ event: 'log', ...data })
modrinthServersConsole.addLegacyLog(data.message) modrinthServersConsole.addLegacyLog(data.message)
} }
const handleLog4j = (data: Archon.Websocket.v0.WSLog4jEvent) => { const handleLog4j = (data: Archon.Websocket.v0.WSLog4jEvent) => {
if (!shouldProcessEvent()) return if (!shouldProcessEvent()) return
modrinthServersConsole.recordWsEvent({ event: 'log4j', ...data })
modrinthServersConsole.addLog4jEvent(data) modrinthServersConsole.addLog4jEvent(data)
} }

View File

@@ -23,6 +23,14 @@
page. (WebSocket Authentication Failed) page. (WebSocket Authentication Failed)
</p> </p>
</div> </div>
<button
v-if="showAdvancedDebugInfo"
class="self-start rounded-lg bg-surface-3 px-3 py-1 text-sm text-contrast hover:brightness-125"
@click="downloadLog4jDebug"
>
Download WS debug JSON
</button>
</div> </div>
</template> </template>
@@ -37,6 +45,15 @@ import { injectModrinthClient, injectModrinthServerContext } from '#ui/providers
import ServerManageStats from './components/ServerManageStats.vue' import ServerManageStats from './components/ServerManageStats.vue'
const props = withDefaults(
defineProps<{
showAdvancedDebugInfo?: boolean
}>(),
{
showAdvancedDebugInfo: false,
},
)
const client = injectModrinthClient() const client = injectModrinthClient()
const { const {
server: _serverData, server: _serverData,
@@ -49,6 +66,14 @@ const {
} = injectModrinthServerContext() } = injectModrinthServerContext()
const modrinthServersConsole = useModrinthServersConsole() const modrinthServersConsole = useModrinthServersConsole()
watch(
() => props.showAdvancedDebugInfo,
(enabled) => {
modrinthServersConsole.setWsEventCaptureEnabled(enabled)
},
{ immediate: true },
)
const crashAnalysis = ref<Mclogs.Insights.v1.InsightsResponse | null>(null) const crashAnalysis = ref<Mclogs.Insights.v1.InsightsResponse | null>(null)
const DISMISS_DURATION_MS = 30 * 60 * 1000 const DISMISS_DURATION_MS = 30 * 60 * 1000
const dismissedUntil = useStorage(`modrinth-crash-dismissed-${serverId}`, 0) const dismissedUntil = useStorage(`modrinth-crash-dismissed-${serverId}`, 0)
@@ -120,4 +145,17 @@ watch(
if (serverPowerState.value === 'crashed') { if (serverPowerState.value === 'crashed') {
void inspectError() void inspectError()
} }
const downloadLog4jDebug = () => {
const events = modrinthServersConsole.getWsEventHistory()
const blob = new Blob([JSON.stringify(events, null, 2)], { type: 'application/json' })
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `ws-debug-${serverId}-${Date.now()}.json`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
}
</script> </script>