fix: prevent duplicate channel action toasts (#5015)

* fix: prevent duplicate channel action toasts

* fix: localize api error fallbacks
This commit is contained in:
yyhhyyyyyy
2026-05-26 10:20:54 +08:00
committed by GitHub
parent a64f26d1d2
commit ad224ecf5b
6 changed files with 182 additions and 81 deletions
+90 -38
View File
@@ -16,8 +16,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import type { AxiosRequestConfig } from 'axios'
import { api } from '@/lib/api'
import { api, type ApiRequestConfig } from '@/lib/api'
import { getGroups as getUserGroups } from '@/features/users/api'
import type {
AddChannelRequest,
@@ -39,11 +38,13 @@ import type {
TagOperationParams,
} from './types'
// Extended API config types
interface ExtendedApiConfig extends AxiosRequestConfig {
skipBusinessError?: boolean
disableDuplicate?: boolean
}
const channelActionConfig = (
config: ApiRequestConfig = {}
): ApiRequestConfig => ({
...config,
skipBusinessError: true,
skipErrorHandler: true,
})
export type CodexOAuthStartResponse = {
success: boolean
@@ -125,7 +126,7 @@ export async function getChannel(id: number): Promise<GetChannelResponse> {
export async function createChannel(
data: AddChannelRequest
): Promise<{ success: boolean; message?: string }> {
const res = await api.post('/api/channel', data)
const res = await api.post('/api/channel', data, channelActionConfig())
return res.data
}
@@ -136,7 +137,11 @@ export async function updateChannel(
id: number,
data: Partial<Channel>
): Promise<{ success: boolean; message?: string; data?: Channel }> {
const res = await api.put('/api/channel/', { id, ...data })
const res = await api.put(
'/api/channel/',
{ id, ...data },
channelActionConfig()
)
return res.data
}
@@ -146,7 +151,7 @@ export async function updateChannel(
export async function deleteChannel(
id: number
): Promise<{ success: boolean; message?: string }> {
const res = await api.delete(`/api/channel/${id}`)
const res = await api.delete(`/api/channel/${id}`, channelActionConfig())
return res.data
}
@@ -156,7 +161,7 @@ export async function deleteChannel(
export async function batchDeleteChannels(
data: BatchDeleteParams
): Promise<{ success: boolean; message?: string; data?: number }> {
const res = await api.post('/api/channel/batch', data)
const res = await api.post('/api/channel/batch', data, channelActionConfig())
return res.data
}
@@ -166,7 +171,11 @@ export async function batchDeleteChannels(
export async function batchSetChannelTag(
data: BatchSetTagParams
): Promise<{ success: boolean; message?: string; data?: number }> {
const res = await api.post('/api/channel/batch/tag', data)
const res = await api.post(
'/api/channel/batch/tag',
data,
channelActionConfig()
)
return res.data
}
@@ -181,7 +190,10 @@ export async function testChannel(
id: number,
params?: { model?: string; endpoint_type?: string; stream?: boolean }
): Promise<ChannelTestResponse> {
const res = await api.get(`/api/channel/test/${id}`, { params })
const res = await api.get(
`/api/channel/test/${id}`,
channelActionConfig({ params })
)
return res.data
}
@@ -191,7 +203,10 @@ export async function testChannel(
export async function updateChannelBalance(
id: number
): Promise<ChannelBalanceResponse> {
const res = await api.get(`/api/channel/update_balance/${id}`)
const res = await api.get(
`/api/channel/update_balance/${id}`,
channelActionConfig()
)
return res.data
}
@@ -201,7 +216,10 @@ export async function updateChannelBalance(
export async function fetchUpstreamModels(
id: number
): Promise<FetchModelsResponse> {
const res = await api.get(`/api/channel/fetch_models/${id}`)
const res = await api.get(
`/api/channel/fetch_models/${id}`,
channelActionConfig()
)
return res.data
}
@@ -212,7 +230,11 @@ export async function copyChannel(
id: number,
params: CopyChannelParams = {}
): Promise<CopyChannelResponse> {
const res = await api.post(`/api/channel/copy/${id}`, null, { params })
const res = await api.post(
`/api/channel/copy/${id}`,
null,
channelActionConfig({ params })
)
return res.data
}
@@ -224,7 +246,11 @@ export async function fixChannelAbilities(): Promise<{
message?: string
data?: { success: number; fails: number }
}> {
const res = await api.post('/api/channel/fix')
const res = await api.post(
'/api/channel/fix',
undefined,
channelActionConfig()
)
return res.data
}
@@ -236,7 +262,7 @@ export async function deleteDisabledChannels(): Promise<{
message?: string
data?: number
}> {
const res = await api.delete('/api/channel/disabled')
const res = await api.delete('/api/channel/disabled', channelActionConfig())
return res.data
}
@@ -248,7 +274,11 @@ export async function getChannelKey(
code?: string
): Promise<{ success: boolean; message?: string; data?: { key: string } }> {
const payload = code ? { code } : undefined
const res = await api.post(`/api/channel/${id}/key`, payload)
const res = await api.post(
`/api/channel/${id}/key`,
payload,
channelActionConfig()
)
return res.data
}
@@ -257,19 +287,21 @@ export async function getChannelKey(
// ============================================================================
export async function startCodexOAuth(): Promise<CodexOAuthStartResponse> {
const config: ExtendedApiConfig = { skipBusinessError: true }
const res = await api.post('/api/channel/codex/oauth/start', {}, config)
const res = await api.post(
'/api/channel/codex/oauth/start',
{},
channelActionConfig()
)
return res.data
}
export async function completeCodexOAuth(
input: string
): Promise<CodexOAuthCompleteResponse> {
const config: ExtendedApiConfig = { skipBusinessError: true }
const res = await api.post(
'/api/channel/codex/oauth/complete',
{ input },
config
channelActionConfig()
)
return res.data
}
@@ -277,11 +309,10 @@ export async function completeCodexOAuth(
export async function refreshCodexCredential(
channelId: number
): Promise<CodexCredentialRefreshResponse> {
const config: ExtendedApiConfig = { skipBusinessError: true }
const res = await api.post(
`/api/channel/${channelId}/codex/refresh`,
{},
config
channelActionConfig()
)
return res.data
}
@@ -289,11 +320,10 @@ export async function refreshCodexCredential(
export async function getCodexUsage(
channelId: number
): Promise<CodexUsageResponse> {
const config: ExtendedApiConfig = {
skipBusinessError: true,
disableDuplicate: true,
}
const res = await api.get(`/api/channel/${channelId}/codex/usage`, config)
const res = await api.get(
`/api/channel/${channelId}/codex/usage`,
channelActionConfig({ disableDuplicate: true })
)
return res.data
}
@@ -307,7 +337,11 @@ export async function getCodexUsage(
export async function manageMultiKeys(
params: MultiKeyManageParams
): Promise<MultiKeyStatusResponse | { success: boolean; message?: string }> {
const res = await api.post('/api/channel/multi_key/manage', params)
const res = await api.post(
'/api/channel/multi_key/manage',
params,
channelActionConfig()
)
return res.data
}
@@ -417,7 +451,11 @@ export async function deleteDisabledMultiKeys(
export async function enableTagChannels(
tag: string
): Promise<{ success: boolean; message?: string }> {
const res = await api.post('/api/channel/tag/enabled', { tag })
const res = await api.post(
'/api/channel/tag/enabled',
{ tag },
channelActionConfig()
)
return res.data
}
@@ -427,7 +465,11 @@ export async function enableTagChannels(
export async function disableTagChannels(
tag: string
): Promise<{ success: boolean; message?: string }> {
const res = await api.post('/api/channel/tag/disabled', { tag })
const res = await api.post(
'/api/channel/tag/disabled',
{ tag },
channelActionConfig()
)
return res.data
}
@@ -437,7 +479,7 @@ export async function disableTagChannels(
export async function editTagChannels(
params: TagOperationParams
): Promise<{ success: boolean; message?: string }> {
const res = await api.put('/api/channel/tag', params)
const res = await api.put('/api/channel/tag', params, channelActionConfig())
return res.data
}
@@ -463,7 +505,11 @@ export async function fetchModels(data: {
type: number
key: string
}): Promise<FetchModelsResponse> {
const res = await api.post('/api/channel/fetch_models', data)
const res = await api.post(
'/api/channel/fetch_models',
data,
channelActionConfig()
)
return res.data
}
@@ -474,7 +520,10 @@ export async function deleteOllamaModel(params: {
channel_id: number
model_name: string
}): Promise<{ success: boolean; message?: string }> {
const res = await api.delete('/api/channel/ollama/delete', { data: params })
const res = await api.delete(
'/api/channel/ollama/delete',
channelActionConfig({ data: params })
)
return res.data
}
@@ -485,7 +534,7 @@ export async function testAllChannels(): Promise<{
success: boolean
message?: string
}> {
const res = await api.get('/api/channel/test')
const res = await api.get('/api/channel/test', channelActionConfig())
return res.data
}
@@ -496,7 +545,10 @@ export async function updateAllChannelsBalance(): Promise<{
success: boolean
message?: string
}> {
const res = await api.get('/api/channel/update_balance')
const res = await api.get(
'/api/channel/update_balance',
channelActionConfig()
)
return res.data
}