mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
fix(bot): resolve tab component cache invalidation issue
This commit is contained in:
@@ -610,7 +610,7 @@
|
|||||||
|
|
||||||
<!-- Export dialog -->
|
<!-- Export dialog -->
|
||||||
<Dialog v-model:open="exportDialogOpen">
|
<Dialog v-model:open="exportDialogOpen">
|
||||||
<DialogContent class="sm:max-w-lg w-[calc(100vw-2rem)] max-w-[calc(100vw-2rem)] sm:w-auto">
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{{ $t('common.export') }} mcpServers</DialogTitle>
|
<DialogTitle>{{ $t('common.export') }} mcpServers</DialogTitle>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|||||||
@@ -111,9 +111,9 @@
|
|||||||
<Toggle
|
<Toggle
|
||||||
:class="`py-4 border border-transparent ${activeTab === tab.value ? 'border-inherit' : ''}`"
|
:class="`py-4 border border-transparent ${activeTab === tab.value ? 'border-inherit' : ''}`"
|
||||||
:model-value="isActive(tab.value as string).value"
|
:model-value="isActive(tab.value as string).value"
|
||||||
@update:model-value="(isSelect:boolean) => {
|
@update:model-value="(isSelect: boolean) => {
|
||||||
if (isSelect) {
|
if (isSelect) {
|
||||||
activeTab=tab.value
|
activeTab = tab.value
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
@@ -127,36 +127,14 @@
|
|||||||
<template #sidebar-footer />
|
<template #sidebar-footer />
|
||||||
|
|
||||||
<template #detail>
|
<template #detail>
|
||||||
<template v-if="activeTab === 'files'">
|
|
||||||
<div class="h-full">
|
|
||||||
<KeepAlive>
|
|
||||||
<BotFiles
|
|
||||||
:bot-id="botId"
|
|
||||||
:bot-type="bot?.type"
|
|
||||||
/>
|
|
||||||
</KeepAlive>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="activeTab === 'mcp'">
|
|
||||||
<div class="h-full relative">
|
|
||||||
<KeepAlive>
|
|
||||||
<BotMcp
|
|
||||||
:bot-id="botId"
|
|
||||||
:bot-type="bot?.type"
|
|
||||||
/>
|
|
||||||
</KeepAlive>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
v-else
|
|
||||||
class="max-h-full h-full"
|
class="max-h-full h-full"
|
||||||
>
|
>
|
||||||
<section class="p-4">
|
<section class="p-4">
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<component
|
<component
|
||||||
:is="activeComponent?.component"
|
:is="activeComponent?.component"
|
||||||
:bot-id="botId"
|
v-bind="activeComponent?.params"
|
||||||
:bot-type="bot?.type"
|
|
||||||
/>
|
/>
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
</section>
|
</section>
|
||||||
@@ -241,7 +219,7 @@ import {
|
|||||||
SidebarMenuItem,
|
SidebarMenuItem,
|
||||||
Toggle
|
Toggle
|
||||||
} from '@memoh/ui'
|
} from '@memoh/ui'
|
||||||
import { computed, ref, watch, onMounted } from 'vue'
|
import { computed, ref, watch, onMounted, toValue } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
@@ -276,7 +254,6 @@ import { useAvatarInitials } from '@/composables/useAvatarInitials'
|
|||||||
import { useSyncedQueryParam } from '@/composables/useSyncedQueryParam'
|
import { useSyncedQueryParam } from '@/composables/useSyncedQueryParam'
|
||||||
import { useBotStatusMeta } from '@/composables/useBotStatusMeta'
|
import { useBotStatusMeta } from '@/composables/useBotStatusMeta'
|
||||||
import MasterDetailSidebarLayout from '@/components/master-detail-sidebar-layout/index.vue'
|
import MasterDetailSidebarLayout from '@/components/master-detail-sidebar-layout/index.vue'
|
||||||
|
|
||||||
type BotCheck = BotsBotCheck
|
type BotCheck = BotsBotCheck
|
||||||
type BotContainerInfo = HandlersGetContainerResponse
|
type BotContainerInfo = HandlersGetContainerResponse
|
||||||
type BotContainerSnapshot = HandlersListSnapshotsResponse extends { snapshots?: (infer T)[] } ? T : never
|
type BotContainerSnapshot = HandlersListSnapshotsResponse extends { snapshots?: (infer T)[] } ? T : never
|
||||||
@@ -285,35 +262,6 @@ const route = useRoute()
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const botId = computed(() => route.params.botId as string)
|
const botId = computed(() => route.params.botId as string)
|
||||||
|
|
||||||
const tabList = [
|
|
||||||
{ value: 'overview', label: 'bots.tabs.overview',component: BotOverview },
|
|
||||||
{ value: 'memory', label: 'bots.tabs.memory',component:BotMemory },
|
|
||||||
{ value: 'channels', label: 'bots.tabs.channels', component: BotChannels },
|
|
||||||
{ value: 'email', label: 'bots.tabs.email', component: BotEmail },
|
|
||||||
{ value: 'container', label: 'bots.tabs.container', component: BotContainer },
|
|
||||||
{ value: 'files', label: 'bots.tabs.files', component: BotFiles },
|
|
||||||
{ value: 'mcp', label: 'bots.tabs.mcp' ,component: BotMcp },
|
|
||||||
{ value: 'subagents', label: 'bots.tabs.subagents',component: BotSubagents },
|
|
||||||
{ value: 'heartbeat', label: 'bots.tabs.heartbeat',component: BotHeartbeat },
|
|
||||||
{ value: 'schedule', label: 'bots.tabs.schedule', component: BotSchedule },
|
|
||||||
{ value: 'history', label: 'bots.tabs.history',component: BotHistory },
|
|
||||||
{ value: 'skills', label: 'bots.tabs.skills',component: BotSkills },
|
|
||||||
{ value: 'settings', label: 'bots.tabs.settings',component: BotSettings }
|
|
||||||
]
|
|
||||||
|
|
||||||
const isActive = (name: string) => computed(() => {
|
|
||||||
return activeTab.value===name
|
|
||||||
})
|
|
||||||
|
|
||||||
const activeComponent = computed(() => {
|
|
||||||
return tabList.find(tab=>tab.value===activeTab.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
const capabilitiesStore = useCapabilitiesStore()
|
|
||||||
onMounted(() => {
|
|
||||||
void capabilitiesStore.load()
|
|
||||||
})
|
|
||||||
|
|
||||||
const { data: bot } = useQuery({
|
const { data: bot } = useQuery({
|
||||||
key: () => ['bot', botId.value],
|
key: () => ['bot', botId.value],
|
||||||
query: async () => {
|
query: async () => {
|
||||||
@@ -322,6 +270,42 @@ const { data: bot } = useQuery({
|
|||||||
},
|
},
|
||||||
enabled: () => !!botId.value,
|
enabled: () => !!botId.value,
|
||||||
})
|
})
|
||||||
|
const tabList = computed(() => {
|
||||||
|
const bot_id = toValue(botId)
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
value: 'overview', label: 'bots.tabs.overview', component: BotOverview, params: {}
|
||||||
|
},
|
||||||
|
{ value: 'memory', label: 'bots.tabs.memory', component: BotMemory, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'channels', label: 'bots.tabs.channels', component: BotChannels, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'email', label: 'bots.tabs.email', component: BotEmail, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'container', label: 'bots.tabs.container', component: BotContainer, params: {} },
|
||||||
|
{ value: 'files', label: 'bots.tabs.files', component: BotFiles, params: { 'bot-id': bot_id, 'bot-type': bot.value?.type } },
|
||||||
|
{ value: 'mcp', label: 'bots.tabs.mcp', component: BotMcp, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'subagents', label: 'bots.tabs.subagents', component: BotSubagents, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'heartbeat', label: 'bots.tabs.heartbeat', component: BotHeartbeat, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'schedule', label: 'bots.tabs.schedule', component: BotSchedule, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'history', label: 'bots.tabs.history', component: BotHistory, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'skills', label: 'bots.tabs.skills', component: BotSkills, params: { 'bot-id': bot_id } },
|
||||||
|
{ value: 'settings', label: 'bots.tabs.settings', component: BotSettings, params: { 'bot-id': bot_id, 'bot-type': bot.value?.type } }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const isActive = (name: string) => computed(() => {
|
||||||
|
return activeTab.value === name
|
||||||
|
})
|
||||||
|
|
||||||
|
const activeComponent = computed(() => {
|
||||||
|
return tabList.value.find(tab => tab.value === activeTab.value)
|
||||||
|
})
|
||||||
|
|
||||||
|
const capabilitiesStore = useCapabilitiesStore()
|
||||||
|
onMounted(() => {
|
||||||
|
void capabilitiesStore.load()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const queryCache = useQueryCache()
|
const queryCache = useQueryCache()
|
||||||
const { mutateAsync: updateBot, isLoading: updateBotLoading } = useMutation({
|
const { mutateAsync: updateBot, isLoading: updateBotLoading } = useMutation({
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, provide, watch, reactive } from 'vue'
|
import { computed, ref, provide, watch, reactive } from 'vue'
|
||||||
import { useQuery, useQueryCache } from '@pinia/colada'
|
import { useQuery} from '@pinia/colada'
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ScrollArea,
|
ScrollArea,
|
||||||
@@ -29,8 +29,6 @@ const { data: providerData } = useQuery({
|
|||||||
return data
|
return data
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const queryCache = useQueryCache()
|
|
||||||
|
|
||||||
const curProvider = ref<EmailProviderResponse>()
|
const curProvider = ref<EmailProviderResponse>()
|
||||||
provide('curEmailProvider', curProvider)
|
provide('curEmailProvider', curProvider)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<DialogTrigger as-child>
|
<DialogTrigger as-child>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
class="w-full"
|
class="w-full mb-4 text-muted-foreground"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
:icon="['fas', 'plus']"
|
:icon="['fas', 'plus']"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
EmptyHeader,
|
EmptyHeader,
|
||||||
EmptyMedia,
|
EmptyMedia,
|
||||||
EmptyTitle,
|
EmptyTitle,
|
||||||
|
Button
|
||||||
} from '@memoh/ui'
|
} from '@memoh/ui'
|
||||||
import { getMemoryProviders } from '@memoh/sdk'
|
import { getMemoryProviders } from '@memoh/sdk'
|
||||||
import type { MemoryprovidersGetResponse } from '@memoh/sdk'
|
import type { MemoryprovidersGetResponse } from '@memoh/sdk'
|
||||||
@@ -129,7 +130,17 @@ const openStatus = reactive({ addOpen: false })
|
|||||||
<EmptyTitle>{{ $t('memoryProvider.emptyTitle') }}</EmptyTitle>
|
<EmptyTitle>{{ $t('memoryProvider.emptyTitle') }}</EmptyTitle>
|
||||||
<EmptyDescription>{{ $t('memoryProvider.emptyDescription') }}</EmptyDescription>
|
<EmptyDescription>{{ $t('memoryProvider.emptyDescription') }}</EmptyDescription>
|
||||||
<EmptyContent>
|
<EmptyContent>
|
||||||
<AddMemoryProvider v-model:open="openStatus.addOpen" />
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="w-full"
|
||||||
|
@click="openStatus.addOpen=true"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon
|
||||||
|
:icon="['fas', 'plus']"
|
||||||
|
class="mr-2"
|
||||||
|
/>
|
||||||
|
{{ $t('memoryProvider.add') }}
|
||||||
|
</Button>
|
||||||
</EmptyContent>
|
</EmptyContent>
|
||||||
</Empty>
|
</Empty>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user