fix(stage-pages): sync active card sessions (#2110)

This commit is contained in:
RainbowBird
2026-07-26 17:45:04 +08:00
committed by GitHub
parent 019d3fa15f
commit 20355670a9
15 changed files with 237 additions and 17 deletions
@@ -77,6 +77,7 @@ const { activeProvider: defaultArtistryProvider } = storeToRefs(artistryStore)
// Determine if we're in edit mode
const isEditMode = computed(() => !!props.cardId)
const isEditingActiveCard = computed(() => isEditMode.value && props.cardId === cardStore.activeCardId)
// Modules configuration
const selectedConsciousnessProvider = ref<string>('')
@@ -303,7 +304,7 @@ watch(() => props.modelValue, (isOpen) => {
const showError = ref<boolean>(false)
const errorMessage = ref<string>('')
function saveCard(card: Card): boolean {
function saveCard(card: Card, activate: boolean): boolean {
const draftResult = safeParseAiriCardDraft(toRaw(card), selectedArtistryConfigStr.value)
if (!draftResult.success) {
showError.value = true
@@ -350,18 +351,24 @@ function saveCard(card: Card): boolean {
} as AiriExtension,
},
}
let savedCardId: string
if (isEditMode.value && props.cardId) {
// Edit mode: update existing card
cardStore.updateCard(props.cardId, cardWithModules)
if (!cardStore.updateCard(props.cardId, cardWithModules)) {
showError.value = true
errorMessage.value = t('settings.pages.card.card_not_found')
return false
}
savedCardId = props.cardId
trackCardEdited({ card_id: props.cardId })
}
else {
const newCardId = cardStore.addCard(cardWithModules, 'scratch')
// A new card becomes the runtime profile immediately so Create does not
// appear to succeed while conversations continue using the previous card.
cardStore.activeCardId = newCardId
savedCardId = cardStore.addCard(cardWithModules, 'scratch')
}
if (activate)
cardStore.activeCardId = savedCardId
modelValue.value = false // Close this
return true
}
@@ -690,11 +697,19 @@ function getDefaultPlaceholder(defaultValue: string | undefined): string {
@click="modelValue = false"
/>
<Button
variant="primary"
:variant="isEditingActiveCard ? 'primary' : 'secondary'"
icon="i-solar:check-circle-bold-duotone"
:label="isEditMode ? t('settings.pages.card.save') : t('settings.pages.card.creation.create')"
:label="t('settings.pages.card.save')"
:disabled="false"
@click="saveCard(card)"
@click="saveCard(card, false)"
/>
<Button
v-if="!isEditingActiveCard"
variant="primary"
icon="i-solar:play-circle-bold-duotone"
:label="t('settings.pages.card.save_and_activate')"
:disabled="false"
@click="saveCard(card, true)"
/>
</div>
</div>
@@ -40,7 +40,7 @@ const isCardCreationDialogOpen = ref(false)
const searchQuery = ref('')
// Sort option
const sortOption = ref('nameAsc')
const sortOption = ref<'nameAsc' | 'nameDesc' | 'recent'>('nameAsc')
const inputFiles = ref<File[]>([])
@@ -96,17 +96,17 @@ const filteredCards = computed<CardItem[]>(() => {
// Sorted filtered cards based on sort option
const sortedFilteredCards = computed<CardItem[]>(() => {
// Create a new array to avoid mutating the source
const sorted = [...filteredCards.value]
if (sortOption.value === 'nameAsc')
return sorted.sort((a, b) => a.name.localeCompare(b.name))
else if (sortOption.value === 'nameDesc')
if (sortOption.value === 'nameDesc')
return sorted.sort((a, b) => b.name.localeCompare(a.name))
else if (sortOption.value === 'recent')
return sorted.sort((a, b) => b.id.localeCompare(a.id))
else
return sorted
// The persisted Map retains insertion order; nanoids are random and cannot
// represent when a card was added.
return sorted.reverse()
})
// Delete confirmation
@@ -157,6 +157,15 @@ function activateCard(id: string) {
activeCardId.value = id
}
watch(activeCardId, (cardId, previousCardId) => {
if (!previousCardId || cardId === previousCardId)
return
const activeCard = cards.value.get(cardId)
if (activeCard)
toast(t('settings.pages.card.activation_notice', { name: activeCard.name }))
})
// Clear editing state when creation/edit dialog closes
watch(isCardCreationDialogOpen, (isOpen) => {
if (!isOpen) {