Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
9dcd3cd4
Unverified
Commit
9dcd3cd4
authored
Mar 04, 2026
by
Wesley Liddick
Committed by
GitHub
Mar 04, 2026
Browse files
Merge pull request #754 from xvhuan/perf/admin-core-large-dataset
perf(admin): 优化后台大数据场景加载性能(仪表盘/用户/账号/Ops)
parents
49767ccc
f6fe5b55
Changes
27
Show whitespace changes
Inline
Side-by-side
frontend/src/api/admin/dashboard.ts
View file @
9dcd3cd4
...
@@ -120,6 +120,31 @@ export interface GroupStatsResponse {
...
@@ -120,6 +120,31 @@ export interface GroupStatsResponse {
end_date
:
string
end_date
:
string
}
}
export
interface
DashboardSnapshotV2Params
extends
TrendParams
{
include_stats
?:
boolean
include_trend
?:
boolean
include_model_stats
?:
boolean
include_group_stats
?:
boolean
include_users_trend
?:
boolean
users_trend_limit
?:
number
}
export
interface
DashboardSnapshotV2Stats
extends
DashboardStats
{
uptime
:
number
}
export
interface
DashboardSnapshotV2Response
{
generated_at
:
string
start_date
:
string
end_date
:
string
granularity
:
string
stats
?:
DashboardSnapshotV2Stats
trend
?:
TrendDataPoint
[]
models
?:
ModelStat
[]
groups
?:
GroupStat
[]
users_trend
?:
UserUsageTrendPoint
[]
}
/**
/**
* Get group usage statistics
* Get group usage statistics
* @param params - Query parameters for filtering
* @param params - Query parameters for filtering
...
@@ -130,6 +155,16 @@ export async function getGroupStats(params?: GroupStatsParams): Promise<GroupSta
...
@@ -130,6 +155,16 @@ export async function getGroupStats(params?: GroupStatsParams): Promise<GroupSta
return
data
return
data
}
}
/**
* Get dashboard snapshot v2 (aggregated response for heavy admin pages).
*/
export
async
function
getSnapshotV2
(
params
?:
DashboardSnapshotV2Params
):
Promise
<
DashboardSnapshotV2Response
>
{
const
{
data
}
=
await
apiClient
.
get
<
DashboardSnapshotV2Response
>
(
'
/admin/dashboard/snapshot-v2
'
,
{
params
})
return
data
}
export
interface
ApiKeyTrendParams
extends
TrendParams
{
export
interface
ApiKeyTrendParams
extends
TrendParams
{
limit
?:
number
limit
?:
number
}
}
...
@@ -233,6 +268,7 @@ export const dashboardAPI = {
...
@@ -233,6 +268,7 @@ export const dashboardAPI = {
getUsageTrend
,
getUsageTrend
,
getModelStats
,
getModelStats
,
getGroupStats
,
getGroupStats
,
getSnapshotV2
,
getApiKeyUsageTrend
,
getApiKeyUsageTrend
,
getUserUsageTrend
,
getUserUsageTrend
,
getBatchUsersUsage
,
getBatchUsersUsage
,
...
...
frontend/src/api/admin/ops.ts
View file @
9dcd3cd4
...
@@ -259,6 +259,13 @@ export interface OpsErrorDistributionResponse {
...
@@ -259,6 +259,13 @@ export interface OpsErrorDistributionResponse {
items
:
OpsErrorDistributionItem
[]
items
:
OpsErrorDistributionItem
[]
}
}
export
interface
OpsDashboardSnapshotV2Response
{
generated_at
:
string
overview
:
OpsDashboardOverview
throughput_trend
:
OpsThroughputTrendResponse
error_trend
:
OpsErrorTrendResponse
}
export
type
OpsOpenAITokenStatsTimeRange
=
'
30m
'
|
'
1h
'
|
'
1d
'
|
'
15d
'
|
'
30d
'
export
type
OpsOpenAITokenStatsTimeRange
=
'
30m
'
|
'
1h
'
|
'
1d
'
|
'
15d
'
|
'
30d
'
export
interface
OpsOpenAITokenStatsItem
{
export
interface
OpsOpenAITokenStatsItem
{
...
@@ -1004,6 +1011,24 @@ export async function getDashboardOverview(
...
@@ -1004,6 +1011,24 @@ export async function getDashboardOverview(
return
data
return
data
}
}
export
async
function
getDashboardSnapshotV2
(
params
:
{
time_range
?:
'
5m
'
|
'
30m
'
|
'
1h
'
|
'
6h
'
|
'
24h
'
start_time
?:
string
end_time
?:
string
platform
?:
string
group_id
?:
number
|
null
mode
?:
OpsQueryMode
},
options
:
OpsRequestOptions
=
{}
):
Promise
<
OpsDashboardSnapshotV2Response
>
{
const
{
data
}
=
await
apiClient
.
get
<
OpsDashboardSnapshotV2Response
>
(
'
/admin/ops/dashboard/snapshot-v2
'
,
{
params
,
signal
:
options
.
signal
})
return
data
}
export
async
function
getThroughputTrend
(
export
async
function
getThroughputTrend
(
params
:
{
params
:
{
time_range
?:
'
5m
'
|
'
30m
'
|
'
1h
'
|
'
6h
'
|
'
24h
'
time_range
?:
'
5m
'
|
'
30m
'
|
'
1h
'
|
'
6h
'
|
'
24h
'
...
@@ -1329,6 +1354,7 @@ async function updateMetricThresholds(thresholds: OpsMetricThresholds): Promise<
...
@@ -1329,6 +1354,7 @@ async function updateMetricThresholds(thresholds: OpsMetricThresholds): Promise<
}
}
export
const
opsAPI
=
{
export
const
opsAPI
=
{
getDashboardSnapshotV2
,
getDashboardOverview
,
getDashboardOverview
,
getThroughputTrend
,
getThroughputTrend
,
getLatencyHistogram
,
getLatencyHistogram
,
...
...
frontend/src/api/admin/users.ts
View file @
9dcd3cd4
...
@@ -22,6 +22,7 @@ export async function list(
...
@@ -22,6 +22,7 @@ export async function list(
role
?:
'
admin
'
|
'
user
'
role
?:
'
admin
'
|
'
user
'
search
?:
string
search
?:
string
attributes
?:
Record
<
number
,
string
>
// attributeId -> value
attributes
?:
Record
<
number
,
string
>
// attributeId -> value
include_subscriptions
?:
boolean
},
},
options
?:
{
options
?:
{
signal
?:
AbortSignal
signal
?:
AbortSignal
...
@@ -33,7 +34,8 @@ export async function list(
...
@@ -33,7 +34,8 @@ export async function list(
page_size
:
pageSize
,
page_size
:
pageSize
,
status
:
filters
?.
status
,
status
:
filters
?.
status
,
role
:
filters
?.
role
,
role
:
filters
?.
role
,
search
:
filters
?.
search
search
:
filters
?.
search
,
include_subscriptions
:
filters
?.
include_subscriptions
}
}
// Add attribute filters as attr[id]=value
// Add attribute filters as attr[id]=value
...
...
frontend/src/views/admin/AccountsView.vue
View file @
9dcd3cd4
...
@@ -359,7 +359,7 @@ const exportingData = ref(false)
...
@@ -359,7 +359,7 @@ const exportingData = ref(false)
const
showColumnDropdown
=
ref
(
false
)
const
showColumnDropdown
=
ref
(
false
)
const
columnDropdownRef
=
ref
<
HTMLElement
|
null
>
(
null
)
const
columnDropdownRef
=
ref
<
HTMLElement
|
null
>
(
null
)
const
hiddenColumns
=
reactive
<
Set
<
string
>>
(
new
Set
())
const
hiddenColumns
=
reactive
<
Set
<
string
>>
(
new
Set
())
const
DEFAULT_HIDDEN_COLUMNS
=
[
'
proxy
'
,
'
notes
'
,
'
priority
'
,
'
rate_multiplier
'
]
const
DEFAULT_HIDDEN_COLUMNS
=
[
'
today_stats
'
,
'
proxy
'
,
'
notes
'
,
'
priority
'
,
'
rate_multiplier
'
]
const
HIDDEN_COLUMNS_KEY
=
'
account-hidden-columns
'
const
HIDDEN_COLUMNS_KEY
=
'
account-hidden-columns
'
// Sorting settings
// Sorting settings
...
@@ -546,7 +546,7 @@ const {
...
@@ -546,7 +546,7 @@ const {
handlePageSizeChange
:
baseHandlePageSizeChange
handlePageSizeChange
:
baseHandlePageSizeChange
}
=
useTableLoader
<
Account
,
any
>
({
}
=
useTableLoader
<
Account
,
any
>
({
fetchFn
:
adminAPI
.
accounts
.
list
,
fetchFn
:
adminAPI
.
accounts
.
list
,
initialParams
:
{
platform
:
''
,
type
:
''
,
status
:
''
,
group
:
''
,
search
:
''
}
initialParams
:
{
platform
:
''
,
type
:
''
,
status
:
''
,
group
:
''
,
search
:
''
,
lite
:
'
1
'
}
}
)
}
)
const
resetAutoRefreshCache
=
()
=>
{
const
resetAutoRefreshCache
=
()
=>
{
...
@@ -689,6 +689,7 @@ const refreshAccountsIncrementally = async () => {
...
@@ -689,6 +689,7 @@ const refreshAccountsIncrementally = async () => {
type
?:
string
type
?:
string
status
?:
string
status
?:
string
search
?:
string
search
?:
string
lite
?:
string
}
,
}
,
{
etag
:
autoRefreshETag
.
value
}
{
etag
:
autoRefreshETag
.
value
}
)
)
...
...
frontend/src/views/admin/DashboardView.vue
View file @
9dcd3cd4
...
@@ -316,6 +316,7 @@ const trendData = ref<TrendDataPoint[]>([])
...
@@ -316,6 +316,7 @@ const trendData = ref<TrendDataPoint[]>([])
const
modelStats
=
ref
<
ModelStat
[]
>
([])
const
modelStats
=
ref
<
ModelStat
[]
>
([])
const
userTrend
=
ref
<
UserUsageTrendPoint
[]
>
([])
const
userTrend
=
ref
<
UserUsageTrendPoint
[]
>
([])
let
chartLoadSeq
=
0
let
chartLoadSeq
=
0
let
usersTrendLoadSeq
=
0
// Helper function to format date in local timezone
// Helper function to format date in local timezone
const
formatLocalDate
=
(
date
:
Date
):
string
=>
{
const
formatLocalDate
=
(
date
:
Date
):
string
=>
{
...
@@ -523,67 +524,74 @@ const onDateRangeChange = (range: {
...
@@ -523,67 +524,74 @@ const onDateRangeChange = (range: {
}
}
// Load data
// Load data
const
loadDashboardStats
=
async
()
=>
{
const
loadDashboardSnapshot
=
async
(
includeStats
:
boolean
)
=>
{
const
currentSeq
=
++
chartLoadSeq
if
(
includeStats
&&
!
stats
.
value
)
{
loading
.
value
=
true
loading
.
value
=
true
try
{
stats
.
value
=
await
adminAPI
.
dashboard
.
getStats
()
}
catch
(
error
)
{
appStore
.
showError
(
t
(
'
admin.dashboard.failedToLoad
'
))
console
.
error
(
'
Error loading dashboard stats:
'
,
error
)
}
finally
{
loading
.
value
=
false
}
}
}
const
loadChartData
=
async
()
=>
{
const
currentSeq
=
++
chartLoadSeq
chartsLoading
.
value
=
true
chartsLoading
.
value
=
true
userTrendLoading
.
value
=
true
try
{
try
{
const
params
=
{
const
response
=
await
adminAPI
.
dashboard
.
getSnapshotV2
(
{
start_date
:
startDate
.
value
,
start_date
:
startDate
.
value
,
end_date
:
endDate
.
value
,
end_date
:
endDate
.
value
,
granularity
:
granularity
.
value
granularity
:
granularity
.
value
,
}
include_stats
:
includeStats
,
include_trend
:
true
,
const
[
trendResponse
,
modelResponse
]
=
await
Promise
.
all
([
include_model_stats
:
true
,
adminAPI
.
dashboard
.
getUsageTrend
(
params
),
include_group_stats
:
false
,
adminAPI
.
dashboard
.
getModelStats
({
start_date
:
startDate
.
value
,
end_date
:
endDate
.
value
})
include_users_trend
:
false
])
})
if
(
currentSeq
!==
chartLoadSeq
)
return
if
(
currentSeq
!==
chartLoadSeq
)
return
trendData
.
value
=
trendResponse
.
trend
||
[]
if
(
includeStats
&&
response
.
stats
)
{
modelStats
.
value
=
modelResponse
.
models
||
[]
stats
.
value
=
response
.
stats
}
trendData
.
value
=
response
.
trend
||
[]
modelStats
.
value
=
response
.
models
||
[]
}
catch
(
error
)
{
}
catch
(
error
)
{
if
(
currentSeq
!==
chartLoadSeq
)
return
if
(
currentSeq
!==
chartLoadSeq
)
return
console
.
error
(
'
Error loading chart data:
'
,
error
)
appStore
.
showError
(
t
(
'
admin.dashboard.failedToLoad
'
))
console
.
error
(
'
Error loading dashboard snapshot:
'
,
error
)
}
finally
{
}
finally
{
if
(
currentSeq
!==
chartLoadSeq
)
return
if
(
currentSeq
!==
chartLoadSeq
)
return
loading
.
value
=
false
chartsLoading
.
value
=
false
chartsLoading
.
value
=
false
}
}
}
const
loadUsersTrend
=
async
()
=>
{
const
currentSeq
=
++
usersTrendLoadSeq
userTrendLoading
.
value
=
true
try
{
try
{
const
params
=
{
const
response
=
await
adminAPI
.
dashboard
.
getUserUsageTrend
(
{
start_date
:
startDate
.
value
,
start_date
:
startDate
.
value
,
end_date
:
endDate
.
value
,
end_date
:
endDate
.
value
,
granularity
:
granularity
.
value
,
granularity
:
granularity
.
value
,
limit
:
12
limit
:
12
}
})
const
userResponse
=
await
adminAPI
.
dashboard
.
getUserUsageTrend
(
params
)
if
(
currentSeq
!==
usersTrendLoadSeq
)
return
if
(
currentSeq
!==
chartLoadSeq
)
return
userTrend
.
value
=
response
.
trend
||
[]
userTrend
.
value
=
userResponse
.
trend
||
[]
}
catch
(
error
)
{
}
catch
(
error
)
{
if
(
currentSeq
!==
chartLoadSeq
)
return
if
(
currentSeq
!==
usersTrendLoadSeq
)
return
console
.
error
(
'
Error loading user trend:
'
,
error
)
console
.
error
(
'
Error loading users trend:
'
,
error
)
userTrend
.
value
=
[]
}
finally
{
}
finally
{
if
(
currentSeq
!==
chart
LoadSeq
)
return
if
(
currentSeq
!==
usersTrend
LoadSeq
)
return
userTrendLoading
.
value
=
false
userTrendLoading
.
value
=
false
}
}
}
}
const
loadDashboardStats
=
async
()
=>
{
await
loadDashboardSnapshot
(
true
)
void
loadUsersTrend
()
}
const
loadChartData
=
async
()
=>
{
await
loadDashboardSnapshot
(
false
)
void
loadUsersTrend
()
}
onMounted
(()
=>
{
onMounted
(()
=>
{
loadDashboardStats
()
loadDashboardStats
()
loadChartData
()
})
})
</
script
>
</
script
>
...
...
frontend/src/views/admin/UsersView.vue
View file @
9dcd3cd4
...
@@ -655,16 +655,28 @@ const saveColumnsToStorage = () => {
...
@@ -655,16 +655,28 @@ const saveColumnsToStorage = () => {
// Toggle column visibility
// Toggle column visibility
const
toggleColumn
=
(
key
:
string
)
=>
{
const
toggleColumn
=
(
key
:
string
)
=>
{
const
wasHidden
=
hiddenColumns
.
has
(
key
)
if
(
hiddenColumns
.
has
(
key
))
{
if
(
hiddenColumns
.
has
(
key
))
{
hiddenColumns
.
delete
(
key
)
hiddenColumns
.
delete
(
key
)
}
else
{
}
else
{
hiddenColumns
.
add
(
key
)
hiddenColumns
.
add
(
key
)
}
}
saveColumnsToStorage
()
saveColumnsToStorage
()
if
(
wasHidden
&&
(
key
===
'
usage
'
||
key
.
startsWith
(
'
attr_
'
)))
{
refreshCurrentPageSecondaryData
()
}
if
(
key
===
'
subscriptions
'
)
{
loadUsers
()
}
}
}
// Check if column is visible (not in hidden set)
// Check if column is visible (not in hidden set)
const
isColumnVisible
=
(
key
:
string
)
=>
!
hiddenColumns
.
has
(
key
)
const
isColumnVisible
=
(
key
:
string
)
=>
!
hiddenColumns
.
has
(
key
)
const
hasVisibleUsageColumn
=
computed
(()
=>
!
hiddenColumns
.
has
(
'
usage
'
))
const
hasVisibleSubscriptionsColumn
=
computed
(()
=>
!
hiddenColumns
.
has
(
'
subscriptions
'
))
const
hasVisibleAttributeColumns
=
computed
(()
=>
attributeDefinitions
.
value
.
some
((
def
)
=>
def
.
enabled
&&
!
hiddenColumns
.
has
(
`attr_
${
def
.
id
}
`
))
)
// Filtered columns based on visibility
// Filtered columns based on visibility
const
columns
=
computed
<
Column
[]
>
(()
=>
const
columns
=
computed
<
Column
[]
>
(()
=>
...
@@ -776,6 +788,60 @@ const editingUser = ref<AdminUser | null>(null)
...
@@ -776,6 +788,60 @@ const editingUser = ref<AdminUser | null>(null)
const
deletingUser
=
ref
<
AdminUser
|
null
>
(
null
)
const
deletingUser
=
ref
<
AdminUser
|
null
>
(
null
)
const
viewingUser
=
ref
<
AdminUser
|
null
>
(
null
)
const
viewingUser
=
ref
<
AdminUser
|
null
>
(
null
)
let
abortController
:
AbortController
|
null
=
null
let
abortController
:
AbortController
|
null
=
null
let
secondaryDataSeq
=
0
const
loadUsersSecondaryData
=
async
(
userIds
:
number
[],
signal
?:
AbortSignal
,
expectedSeq
?:
number
)
=>
{
if
(
userIds
.
length
===
0
)
return
const
tasks
:
Promise
<
void
>
[]
=
[]
if
(
hasVisibleUsageColumn
.
value
)
{
tasks
.
push
(
(
async
()
=>
{
try
{
const
usageResponse
=
await
adminAPI
.
dashboard
.
getBatchUsersUsage
(
userIds
)
if
(
signal
?.
aborted
)
return
if
(
typeof
expectedSeq
===
'
number
'
&&
expectedSeq
!==
secondaryDataSeq
)
return
usageStats
.
value
=
usageResponse
.
stats
}
catch
(
e
)
{
if
(
signal
?.
aborted
)
return
console
.
error
(
'
Failed to load usage stats:
'
,
e
)
}
})()
)
}
if
(
attributeDefinitions
.
value
.
length
>
0
&&
hasVisibleAttributeColumns
.
value
)
{
tasks
.
push
(
(
async
()
=>
{
try
{
const
attrResponse
=
await
adminAPI
.
userAttributes
.
getBatchUserAttributes
(
userIds
)
if
(
signal
?.
aborted
)
return
if
(
typeof
expectedSeq
===
'
number
'
&&
expectedSeq
!==
secondaryDataSeq
)
return
userAttributeValues
.
value
=
attrResponse
.
attributes
}
catch
(
e
)
{
if
(
signal
?.
aborted
)
return
console
.
error
(
'
Failed to load user attribute values:
'
,
e
)
}
})()
)
}
if
(
tasks
.
length
>
0
)
{
await
Promise
.
allSettled
(
tasks
)
}
}
const
refreshCurrentPageSecondaryData
=
()
=>
{
const
userIds
=
users
.
value
.
map
((
u
)
=>
u
.
id
)
if
(
userIds
.
length
===
0
)
return
const
seq
=
++
secondaryDataSeq
void
loadUsersSecondaryData
(
userIds
,
undefined
,
seq
)
}
// Action Menu State
// Action Menu State
const
activeMenuId
=
ref
<
number
|
null
>
(
null
)
const
activeMenuId
=
ref
<
number
|
null
>
(
null
)
...
@@ -913,7 +979,8 @@ const loadUsers = async () => {
...
@@ -913,7 +979,8 @@ const loadUsers = async () => {
role
:
filters
.
role
as
any
,
role
:
filters
.
role
as
any
,
status
:
filters
.
status
as
any
,
status
:
filters
.
status
as
any
,
search
:
searchQuery
.
value
||
undefined
,
search
:
searchQuery
.
value
||
undefined
,
attributes
:
Object
.
keys
(
attrFilters
).
length
>
0
?
attrFilters
:
undefined
attributes
:
Object
.
keys
(
attrFilters
).
length
>
0
?
attrFilters
:
undefined
,
include_subscriptions
:
hasVisibleSubscriptionsColumn
.
value
},
},
{
signal
}
{
signal
}
)
)
...
@@ -923,38 +990,17 @@ const loadUsers = async () => {
...
@@ -923,38 +990,17 @@ const loadUsers = async () => {
users
.
value
=
response
.
items
users
.
value
=
response
.
items
pagination
.
total
=
response
.
total
pagination
.
total
=
response
.
total
pagination
.
pages
=
response
.
pages
pagination
.
pages
=
response
.
pages
usageStats
.
value
=
{}
userAttributeValues
.
value
=
{}
//
Load usage stats and attribute values for all users in the li
st
//
Defer heavy secondary data so table can render fir
st
.
if
(
response
.
items
.
length
>
0
)
{
if
(
response
.
items
.
length
>
0
)
{
const
userIds
=
response
.
items
.
map
((
u
)
=>
u
.
id
)
const
userIds
=
response
.
items
.
map
((
u
)
=>
u
.
id
)
// Load usage stats
const
seq
=
++
secondaryDataSeq
try
{
window
.
setTimeout
(()
=>
{
const
usageResponse
=
await
adminAPI
.
dashboard
.
getBatchUsersUsage
(
userIds
)
if
(
signal
.
aborted
||
seq
!==
secondaryDataSeq
)
return
if
(
signal
.
aborted
)
{
void
loadUsersSecondaryData
(
userIds
,
signal
,
seq
)
return
},
50
)
}
usageStats
.
value
=
usageResponse
.
stats
}
catch
(
e
)
{
if
(
signal
.
aborted
)
{
return
}
console
.
error
(
'
Failed to load usage stats:
'
,
e
)
}
// Load attribute values
if
(
attributeDefinitions
.
value
.
length
>
0
)
{
try
{
const
attrResponse
=
await
adminAPI
.
userAttributes
.
getBatchUserAttributes
(
userIds
)
if
(
signal
.
aborted
)
{
return
}
userAttributeValues
.
value
=
attrResponse
.
attributes
}
catch
(
e
)
{
if
(
signal
.
aborted
)
{
return
}
console
.
error
(
'
Failed to load user attribute values:
'
,
e
)
}
}
}
}
}
catch
(
error
:
any
)
{
}
catch
(
error
:
any
)
{
const
errorInfo
=
error
as
{
name
?:
string
;
code
?:
string
}
const
errorInfo
=
error
as
{
name
?:
string
;
code
?:
string
}
...
...
frontend/src/views/admin/ops/OpsDashboard.vue
View file @
9dcd3cd4
...
@@ -586,6 +586,32 @@ async function refreshThroughputTrendWithCancel(fetchSeq: number, signal: AbortS
...
@@ -586,6 +586,32 @@ async function refreshThroughputTrendWithCancel(fetchSeq: number, signal: AbortS
}
}
}
}
async
function
refreshCoreSnapshotWithCancel
(
fetchSeq
:
number
,
signal
:
AbortSignal
)
{
if
(
!
opsEnabled
.
value
)
return
loadingTrend
.
value
=
true
loadingErrorTrend
.
value
=
true
try
{
const
data
=
await
opsAPI
.
getDashboardSnapshotV2
(
buildApiParams
(),
{
signal
})
if
(
fetchSeq
!==
dashboardFetchSeq
)
return
overview
.
value
=
data
.
overview
throughputTrend
.
value
=
data
.
throughput_trend
errorTrend
.
value
=
data
.
error_trend
}
catch
(
err
:
any
)
{
if
(
fetchSeq
!==
dashboardFetchSeq
||
isCanceledRequest
(
err
))
return
// Fallback to legacy split endpoints when snapshot endpoint is unavailable.
await
Promise
.
all
([
refreshOverviewWithCancel
(
fetchSeq
,
signal
),
refreshThroughputTrendWithCancel
(
fetchSeq
,
signal
),
refreshErrorTrendWithCancel
(
fetchSeq
,
signal
)
])
}
finally
{
if
(
fetchSeq
===
dashboardFetchSeq
)
{
loadingTrend
.
value
=
false
loadingErrorTrend
.
value
=
false
}
}
}
async
function
refreshLatencyHistogramWithCancel
(
fetchSeq
:
number
,
signal
:
AbortSignal
)
{
async
function
refreshLatencyHistogramWithCancel
(
fetchSeq
:
number
,
signal
:
AbortSignal
)
{
if
(
!
opsEnabled
.
value
)
return
if
(
!
opsEnabled
.
value
)
return
loadingLatency
.
value
=
true
loadingLatency
.
value
=
true
...
@@ -640,6 +666,14 @@ async function refreshErrorDistributionWithCancel(fetchSeq: number, signal: Abor
...
@@ -640,6 +666,14 @@ async function refreshErrorDistributionWithCancel(fetchSeq: number, signal: Abor
}
}
}
}
async
function
refreshDeferredPanels
(
fetchSeq
:
number
,
signal
:
AbortSignal
)
{
if
(
!
opsEnabled
.
value
)
return
await
Promise
.
all
([
refreshLatencyHistogramWithCancel
(
fetchSeq
,
signal
),
refreshErrorDistributionWithCancel
(
fetchSeq
,
signal
)
])
}
function
isOpsDisabledError
(
err
:
unknown
):
boolean
{
function
isOpsDisabledError
(
err
:
unknown
):
boolean
{
return
(
return
(
!!
err
&&
!!
err
&&
...
@@ -662,12 +696,8 @@ async function fetchData() {
...
@@ -662,12 +696,8 @@ async function fetchData() {
errorMessage
.
value
=
''
errorMessage
.
value
=
''
try
{
try
{
await
Promise
.
all
([
await
Promise
.
all
([
refreshOverviewWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshCoreSnapshotWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshThroughputTrendWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshSwitchTrendWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshSwitchTrendWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshLatencyHistogramWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshErrorTrendWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
),
refreshErrorDistributionWithCancel
(
fetchSeq
,
dashboardFetchController
.
signal
)
])
])
if
(
fetchSeq
!==
dashboardFetchSeq
)
return
if
(
fetchSeq
!==
dashboardFetchSeq
)
return
...
@@ -680,6 +710,9 @@ async function fetchData() {
...
@@ -680,6 +710,9 @@ async function fetchData() {
if
(
autoRefreshEnabled
.
value
)
{
if
(
autoRefreshEnabled
.
value
)
{
autoRefreshCountdown
.
value
=
Math
.
floor
(
autoRefreshIntervalMs
.
value
/
1000
)
autoRefreshCountdown
.
value
=
Math
.
floor
(
autoRefreshIntervalMs
.
value
/
1000
)
}
}
// Defer non-core visual panels to reduce initial blocking.
void
refreshDeferredPanels
(
fetchSeq
,
dashboardFetchController
.
signal
)
}
catch
(
err
)
{
}
catch
(
err
)
{
if
(
!
isOpsDisabledError
(
err
))
{
if
(
!
isOpsDisabledError
(
err
))
{
console
.
error
(
'
[ops] failed to fetch dashboard data
'
,
err
)
console
.
error
(
'
[ops] failed to fetch dashboard data
'
,
err
)
...
...
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment