mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
fix: clear loading on request failure
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
"@xterm/addon-fit": "^0.11.0",
|
||||
"@xterm/addon-serialize": "^0.14.0",
|
||||
"@xterm/xterm": "^6.0.0",
|
||||
"animate.css": "^4.1.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"echarts": "^6.0.0",
|
||||
"katex": "^0.16.28",
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
|
||||
<!-- Compatibilities (chat only) -->
|
||||
<div v-if="selectedType === 'chat'">
|
||||
<Label class="mb-2">
|
||||
<Label class="mb-4">
|
||||
{{ $t('models.compatibilities') }}
|
||||
</Label>
|
||||
<div class="flex flex-wrap gap-3 mt-2">
|
||||
|
||||
@@ -3,6 +3,7 @@ import './style.css'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import { setupApiClient } from './lib/api-client'
|
||||
import 'animate.css'
|
||||
|
||||
// Configure SDK client before anything else
|
||||
setupApiClient()
|
||||
|
||||
@@ -52,79 +52,84 @@
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="bindingsLoading"
|
||||
class="flex items-center gap-2 text-xs text-muted-foreground p-4"
|
||||
>
|
||||
<Spinner />
|
||||
<span>{{ $t('common.loading') }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="!bindings?.length"
|
||||
class="rounded-md border p-4"
|
||||
>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ $t('bots.email.noBindings') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="space-y-2"
|
||||
<Transition
|
||||
enter-active-class="animate__fadeIn animate__animated"
|
||||
leave-active-class="animate__fadeOut"
|
||||
mode="out-in"
|
||||
>
|
||||
<div
|
||||
v-for="binding in bindings"
|
||||
:key="binding.id"
|
||||
v-if="bindingsLoading"
|
||||
class="flex items-center gap-2 text-xs text-muted-foreground p-4"
|
||||
>
|
||||
<Spinner />
|
||||
<span>{{ $t('common.loading') }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="!bindings?.length"
|
||||
class="rounded-md border p-4"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="min-w-0">
|
||||
<p class="font-medium text-xs">
|
||||
{{ providerNameMap[binding.email_provider_id!] || binding.email_provider_id }}
|
||||
</p>
|
||||
<p
|
||||
v-if="binding.email_address"
|
||||
class="text-xs text-muted-foreground mt-0.5"
|
||||
>
|
||||
{{ binding.email_address }}
|
||||
</p>
|
||||
</div>
|
||||
<ConfirmPopover
|
||||
:message="$t('bots.email.unbindConfirm')"
|
||||
:loading="deletingId === binding.id"
|
||||
@confirm="handleDeleteBinding(binding.id!)"
|
||||
>
|
||||
<template #trigger>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ $t('bots.email.noBindings') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else
|
||||
class="space-y-2"
|
||||
>
|
||||
<div
|
||||
v-for="binding in bindings"
|
||||
:key="binding.id"
|
||||
class="rounded-md border p-4"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="min-w-0">
|
||||
<p class="font-medium text-xs">
|
||||
{{ providerNameMap[binding.email_provider_id!] || binding.email_provider_id }}
|
||||
</p>
|
||||
<p
|
||||
v-if="binding.email_address"
|
||||
class="text-xs text-muted-foreground mt-0.5"
|
||||
>
|
||||
{{ $t('bots.email.unbind') }}
|
||||
</Button>
|
||||
</template>
|
||||
</ConfirmPopover>
|
||||
</div>
|
||||
<Separator class="my-3" />
|
||||
<div class="flex gap-6 text-xs">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<Switch
|
||||
:model-value="binding.can_read"
|
||||
@update:model-value="(v) => handleTogglePerm(binding, 'can_read', !!v)"
|
||||
/>
|
||||
<span>{{ $t('bots.email.canRead') }}</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<Switch
|
||||
:model-value="binding.can_write"
|
||||
@update:model-value="(v) => handleTogglePerm(binding, 'can_write', !!v)"
|
||||
/>
|
||||
<span>{{ $t('bots.email.canWrite') }}</span>
|
||||
</label>
|
||||
{{ binding.email_address }}
|
||||
</p>
|
||||
</div>
|
||||
<ConfirmPopover
|
||||
:message="$t('bots.email.unbindConfirm')"
|
||||
:loading="deletingId === binding.id"
|
||||
@confirm="handleDeleteBinding(binding.id!)"
|
||||
>
|
||||
<template #trigger>
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
>
|
||||
{{ $t('bots.email.unbind') }}
|
||||
</Button>
|
||||
</template>
|
||||
</ConfirmPopover>
|
||||
</div>
|
||||
<Separator class="my-3" />
|
||||
<div class="flex gap-6 text-xs">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<Switch
|
||||
:model-value="binding.can_read"
|
||||
@update:model-value="(v) => handleTogglePerm(binding, 'can_read', !!v)"
|
||||
/>
|
||||
<span>{{ $t('bots.email.canRead') }}</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<Switch
|
||||
:model-value="binding.can_write"
|
||||
@update:model-value="(v) => handleTogglePerm(binding, 'can_write', !!v)"
|
||||
/>
|
||||
<span>{{ $t('bots.email.canWrite') }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
@@ -578,7 +578,7 @@
|
||||
<p class="text-xs text-muted-foreground mt-2">
|
||||
{{ $t('mcp.importHint') }}
|
||||
</p>
|
||||
<div class="h-[350px] rounded-md border overflow-hidden mt-3">
|
||||
<div class="h-87.5 rounded-md border overflow-hidden mt-3">
|
||||
<MonacoEditor
|
||||
v-model="importJson"
|
||||
language="json"
|
||||
@@ -610,7 +610,7 @@
|
||||
<DialogHeader>
|
||||
<DialogTitle>{{ $t('common.export') }} mcpServers</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div class="h-[350px] rounded-md border overflow-hidden mt-4">
|
||||
<div class="h-87.5 rounded-md border overflow-hidden mt-4">
|
||||
<MonacoEditor
|
||||
:model-value="exportJson"
|
||||
language="json"
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
<!-- Charts Section -->
|
||||
<div
|
||||
v-if="showChartSection"
|
||||
class="h-[240px] border-t flex flex-col bg-muted/5 shrink-0"
|
||||
class="h-60 border-t flex flex-col bg-muted/5 shrink-0"
|
||||
>
|
||||
<div class="px-3 py-1.5 border-b bg-muted/10 flex items-center justify-between shrink-0">
|
||||
<h5 class="text-[10px] font-bold uppercase tracking-wider text-muted-foreground/70">
|
||||
@@ -222,7 +222,7 @@
|
||||
<h3 class="text-xs font-medium text-foreground">
|
||||
{{ $t('bots.memory.title') }}
|
||||
</h3>
|
||||
<p class="text-xs mt-1 max-w-[240px]">
|
||||
<p class="text-xs mt-1 max-w-60">
|
||||
Select a file from the sidebar to view or edit, or create a new one to persist long-term information for your bot.
|
||||
</p>
|
||||
<Button
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
name="name"
|
||||
>
|
||||
<FormItem>
|
||||
<Label :for="componentField.id || 'browser-context-name'">
|
||||
<Label :for="'browser-context-name'">
|
||||
{{ $t('browser.name') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
:id="componentField.id || 'browser-context-name'"
|
||||
:id="'browser-context-name'"
|
||||
type="text"
|
||||
:placeholder="$t('browser.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
@@ -78,7 +78,10 @@ const { mutateAsync: createMutation, isLoading } = useMutation({
|
||||
})
|
||||
return result
|
||||
},
|
||||
onSettled: () => queryCache.invalidateQueries({ key: ['browser-contexts'] }),
|
||||
onSettled: () => queryCache.invalidateQueries({ key: ['browser-contexts'] }).catch((err)=>{console.error(err)}),
|
||||
onError: (_, __, previous) => {
|
||||
queryCache.setQueryData(['browser-contexts'], previous)
|
||||
},
|
||||
})
|
||||
|
||||
const schema = toTypedSchema(z.object({
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
name="name"
|
||||
>
|
||||
<FormItem>
|
||||
<Label :for="componentField.id || 'email-provider-name'">
|
||||
<Label :for="'email-provider-name'">
|
||||
{{ $t('common.name') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
:id="componentField.id || 'email-provider-name'"
|
||||
:id="'email-provider-name'"
|
||||
type="text"
|
||||
:placeholder="$t('common.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
@@ -44,13 +44,13 @@
|
||||
name="provider"
|
||||
>
|
||||
<FormItem>
|
||||
<Label :for="componentField.id || 'email-provider-type'">
|
||||
<Label :for=" 'email-provider-type'">
|
||||
{{ $t('email.providerType') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Select v-bind="componentField">
|
||||
<SelectTrigger
|
||||
:id="componentField.id || 'email-provider-type'"
|
||||
:id="'email-provider-type'"
|
||||
class="w-full"
|
||||
>
|
||||
<SelectValue :placeholder="$t('common.typePlaceholder')" />
|
||||
|
||||
@@ -25,12 +25,12 @@
|
||||
name="name"
|
||||
>
|
||||
<FormItem>
|
||||
<Label :for="componentField.id || 'email-provider-name'">
|
||||
<Label :for="'email-provider-name'">
|
||||
{{ $t('common.name') }}
|
||||
</Label>
|
||||
<FormControl>
|
||||
<Input
|
||||
:id="componentField.id || 'email-provider-name'"
|
||||
:id="'email-provider-name'"
|
||||
type="text"
|
||||
:placeholder="$t('common.namePlaceholder')"
|
||||
v-bind="componentField"
|
||||
@@ -68,17 +68,17 @@
|
||||
>
|
||||
<Input
|
||||
:id="`email-field-${field.key}`"
|
||||
v-model="configData[field.key]"
|
||||
:type="visibleSecrets[field.key] ? 'text' : 'password'"
|
||||
v-model="configData[field.key!] as string"
|
||||
:type="visibleSecrets[field.key!] ? 'text' : 'password'"
|
||||
:placeholder="field.example ? String(field.example) : ''"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute right-2 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground"
|
||||
@click="visibleSecrets[field.key] = !visibleSecrets[field.key]"
|
||||
@click="visibleSecrets[field.key!] = !visibleSecrets[field.key!]"
|
||||
>
|
||||
<component
|
||||
:is="visibleSecrets[field.key] ? EyeOff : Eye"
|
||||
:is="visibleSecrets[field.key!] ? EyeOff : Eye"
|
||||
class="size-3.5"
|
||||
/>
|
||||
</button>
|
||||
@@ -86,22 +86,22 @@
|
||||
|
||||
<Switch
|
||||
v-else-if="field.type === 'bool'"
|
||||
:model-value="!!configData[field.key]"
|
||||
@update:model-value="(val) => configData[field.key] = !!val"
|
||||
:model-value="!!configData[field.key!]"
|
||||
@update:model-value="(val) => configData[field.key!] = !!val"
|
||||
/>
|
||||
|
||||
<Input
|
||||
v-else-if="field.type === 'number'"
|
||||
:id="`email-field-${field.key}`"
|
||||
v-model.number="configData[field.key]"
|
||||
v-model.number="configData[field.key!] as string"
|
||||
type="number"
|
||||
:placeholder="field.example ? String(field.example) : ''"
|
||||
/>
|
||||
|
||||
<Select
|
||||
v-else-if="field.type === 'enum' && field.enum"
|
||||
:model-value="String(configData[field.key] || '')"
|
||||
@update:model-value="(val) => configData[field.key] = val"
|
||||
:model-value="String(configData[field.key!] || '')"
|
||||
@update:model-value="(val) => configData[field.key!] = val"
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue :placeholder="field.title || field.key" />
|
||||
@@ -120,7 +120,7 @@
|
||||
<Input
|
||||
v-else
|
||||
:id="`email-field-${field.key}`"
|
||||
v-model="configData[field.key]"
|
||||
v-model="configData[field.key !] as string"
|
||||
type="text"
|
||||
:placeholder="field.example ? String(field.example) : ''"
|
||||
/>
|
||||
@@ -133,7 +133,7 @@
|
||||
class="mt-6 p-4 border rounded-lg bg-muted/30"
|
||||
>
|
||||
<div class="flex flex-wrap items-start justify-between gap-4">
|
||||
<div class="flex-1 min-w-[220px]">
|
||||
<div class="flex-1 min-w-55">
|
||||
<p class="text-xs font-medium">
|
||||
{{ $t('email.oauth.title') }}
|
||||
</p>
|
||||
|
||||
Generated
+8
@@ -131,6 +131,9 @@ importers:
|
||||
'@xterm/xterm':
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0
|
||||
animate.css:
|
||||
specifier: ^4.1.1
|
||||
version: 4.1.1
|
||||
dotenv:
|
||||
specifier: ^17.2.3
|
||||
version: 17.2.3
|
||||
@@ -2543,6 +2546,9 @@ packages:
|
||||
alien-signals@3.1.2:
|
||||
resolution: {integrity: sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==}
|
||||
|
||||
animate.css@4.1.1:
|
||||
resolution: {integrity: sha512-+mRmCTv6SbCmtYJCN4faJMNFVNN5EuCTTprDTAo7YzIGji2KADmakjVA3+8mVDkZ2Bf09vayB35lSQIex2+QaQ==}
|
||||
|
||||
ansi-colors@4.1.3:
|
||||
resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -6939,6 +6945,8 @@ snapshots:
|
||||
|
||||
alien-signals@3.1.2: {}
|
||||
|
||||
animate.css@4.1.1: {}
|
||||
|
||||
ansi-colors@4.1.3: {}
|
||||
|
||||
ansi-escapes@7.3.0:
|
||||
|
||||
Reference in New Issue
Block a user