fix(stage-ui): recover stale stage model selection (#2033)

This commit is contained in:
Ryanba
2026-07-17 17:53:38 +08:00
committed by GitHub
parent fb2b3f5ce9
commit 88c4790770
2 changed files with 71 additions and 1 deletions
@@ -0,0 +1,63 @@
import type { DisplayModelURL } from '../display-models'
import { createPinia, setActivePinia } from 'pinia'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { DisplayModelFormat, useDisplayModelsStore } from '../display-models'
import { useSettingsStageModel } from './stage-model'
vi.mock('@proj-airi/stage-shared/composables', async () => {
const { refManualReset } = await import('@vueuse/core')
return {
useLocalStorageManualReset: (_key: string, value: string) => refManualReset(value),
}
})
vi.mock('@vueuse/core', async (importOriginal) => {
const actual = await importOriginal<typeof import('@vueuse/core')>()
return {
...actual,
useEventListener: vi.fn(),
}
})
describe('settings stage model store', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
// https://github.com/moeru-ai/airi/issues/1984
it('issue #1984: falls back to the default preset when a custom stage model is missing', async () => {
const fallbackModel: DisplayModelURL = {
id: 'preset-live2d-1',
format: DisplayModelFormat.Live2dZip,
type: 'url',
url: 'https://example.com/preset-live2d.zip',
name: 'Preset Live2D',
importedAt: 1,
}
const displayModelsStore = useDisplayModelsStore()
const getDisplayModelSpy = vi.spyOn(displayModelsStore, 'getDisplayModel').mockImplementation(async (id) => {
if (id === 'display-model-missing')
return undefined
if (id === fallbackModel.id)
return fallbackModel
return undefined
})
const store = useSettingsStageModel()
store.stageModelSelected = 'display-model-missing'
await store.initializeStageModel()
expect(store.stageModelSelected).toBe(fallbackModel.id)
expect(store.stageModelSelectedDisplayModel).toEqual(fallbackModel)
expect(store.stageModelSelectedUrl).toBe(fallbackModel.url)
expect(store.stageModelRenderer).toBe('live2d')
expect(getDisplayModelSpy).toHaveBeenCalledWith('display-model-missing')
expect(getDisplayModelSpy).toHaveBeenCalledWith(fallbackModel.id)
})
})
@@ -14,8 +14,9 @@ export const useSettingsStageModel = defineStore('settings-stage-model', () => {
const displayModelsStore = useDisplayModelsStore()
let stageModelUpdateSequence = 0
const stageModelStorageKey = 'settings/stage/model'
const defaultStageModelId = 'preset-live2d-1'
const stageModelSelectedState = useLocalStorageManualReset<string>(stageModelStorageKey, 'preset-live2d-1')
const stageModelSelectedState = useLocalStorageManualReset<string>(stageModelStorageKey, defaultStageModelId)
const stageModelSelected = computed<string>({
get: () => stageModelSelectedState.value,
set: (value) => {
@@ -77,6 +78,12 @@ export const useSettingsStageModel = defineStore('settings-stage-model', () => {
return
if (!model) {
if (selectedModelId !== defaultStageModelId) {
stageModelSelectedState.value = defaultStageModelId
await updateStageModel()
return
}
replaceStageModelUrl(undefined)
stageModelSelectedDisplayModel.value = undefined
stageModelBuiltInRenderer.value = 'disabled'