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
d08757ce
Commit
d08757ce
authored
Apr 21, 2026
by
IanShaw027
Browse files
refactor(admin): remove auth migration reports
parent
c624cce8
Changes
28
Expand all
Hide whitespace changes
Inline
Side-by-side
frontend/src/i18n/locales/en.ts
View file @
d08757ce
...
...
@@ -1438,8 +1438,8 @@ export default {
usage
:
'
Usage
'
,
concurrency
:
'
Concurrency
'
,
status
:
'
Status
'
,
lastLogin
:
'
Last Login
'
,
lastActive
:
'
Last Active
'
,
lastUsed
:
'
Last Used
'
,
created
:
'
Created
'
,
actions
:
'
Actions
'
},
...
...
frontend/src/i18n/locales/zh.ts
View file @
d08757ce
...
...
@@ -1464,8 +1464,8 @@ export default {
usage
:
'
用量
'
,
concurrency
:
'
并发数
'
,
status
:
'
状态
'
,
last
Login
:
'
最后
登录
'
,
last
Active
:
'
最后使用
'
,
last
Active
:
'
最后
活跃时间
'
,
last
Used
:
'
最后使用
时间
'
,
created
:
'
创建时间
'
,
actions
:
'
操作
'
},
...
...
frontend/src/router/index.ts
View file @
d08757ce
...
...
@@ -341,16 +341,6 @@ const routes: RouteRecordRaw[] = [
descriptionKey
:
'
admin.users.description
'
}
},
{
path
:
'
/admin/users/auth-identity-migration-reports
'
,
name
:
'
AdminAuthIdentityMigrationReports
'
,
component
:
()
=>
import
(
'
@/views/admin/AuthIdentityMigrationReportsView.vue
'
),
meta
:
{
requiresAuth
:
true
,
requiresAdmin
:
true
,
title
:
'
Auth Identity Migration Reports
'
}
},
{
path
:
'
/admin/groups
'
,
name
:
'
AdminGroups
'
,
...
...
frontend/src/types/index.ts
View file @
d08757ce
...
...
@@ -84,7 +84,6 @@ export interface User {
balance_notify_threshold
:
number
|
null
balance_notify_extra_emails
:
NotifyEmailEntry
[]
subscriptions
?:
UserSubscription
[]
// User's active subscriptions
last_login_at
?:
string
|
null
last_active_at
?:
string
|
null
created_at
:
string
updated_at
:
string
...
...
frontend/src/views/admin/AuthIdentityMigrationReportsView.vue
deleted
100644 → 0
View file @
c624cce8
This diff is collapsed.
Click to expand it.
frontend/src/views/admin/UsersView.vue
View file @
d08757ce
...
...
@@ -712,8 +712,8 @@ const allColumns = computed<Column[]>(() => [
{
key
:
'
usage
'
,
label
:
t
(
'
admin.users.columns.usage
'
),
sortable
:
false
},
{
key
:
'
concurrency
'
,
label
:
t
(
'
admin.users.columns.concurrency
'
),
sortable
:
true
},
{
key
:
'
status
'
,
label
:
t
(
'
admin.users.columns.status
'
),
sortable
:
true
},
{
key
:
'
last_used_at
'
,
label
:
t
(
'
admin.users.columns.lastUsed
'
),
sortable
:
true
},
{
key
:
'
last_active_at
'
,
label
:
t
(
'
admin.users.columns.lastActive
'
),
sortable
:
true
},
{
key
:
'
last_used_at
'
,
label
:
t
(
'
admin.users.columns.lastUsed
'
),
sortable
:
true
},
{
key
:
'
created_at
'
,
label
:
t
(
'
admin.users.columns.created
'
),
sortable
:
true
},
{
key
:
'
actions
'
,
label
:
t
(
'
admin.users.columns.actions
'
),
sortable
:
false
}
])
...
...
frontend/src/views/admin/__tests__/AuthIdentityMigrationReportsView.spec.ts
deleted
100644 → 0
View file @
c624cce8
import
{
beforeEach
,
describe
,
expect
,
it
,
vi
}
from
'
vitest
'
import
{
flushPromises
,
mount
}
from
'
@vue/test-utils
'
import
{
defineComponent
,
h
}
from
'
vue
'
import
AuthIdentityMigrationReportsView
from
'
../AuthIdentityMigrationReportsView.vue
'
const
{
bindUserAuthIdentity
,
getAuthIdentityMigrationReportSummary
,
listAuthIdentityMigrationReports
,
resolveAuthIdentityMigrationReport
,
}
=
vi
.
hoisted
(()
=>
({
bindUserAuthIdentity
:
vi
.
fn
(),
getAuthIdentityMigrationReportSummary
:
vi
.
fn
(),
listAuthIdentityMigrationReports
:
vi
.
fn
(),
resolveAuthIdentityMigrationReport
:
vi
.
fn
(),
}))
const
{
showError
,
showSuccess
}
=
vi
.
hoisted
(()
=>
({
showError
:
vi
.
fn
(),
showSuccess
:
vi
.
fn
(),
}))
vi
.
mock
(
'
@/api/admin
'
,
()
=>
({
adminAPI
:
{
users
:
{
bindUserAuthIdentity
,
getAuthIdentityMigrationReportSummary
,
listAuthIdentityMigrationReports
,
resolveAuthIdentityMigrationReport
,
},
},
}))
vi
.
mock
(
'
@/stores/app
'
,
()
=>
({
useAppStore
:
()
=>
({
showError
,
showSuccess
,
}),
}))
vi
.
mock
(
'
vue-i18n
'
,
async
()
=>
{
const
actual
=
await
vi
.
importActual
<
typeof
import
(
'
vue-i18n
'
)
>
(
'
vue-i18n
'
)
return
{
...
actual
,
useI18n
:
()
=>
({
locale
:
{
value
:
'
en
'
},
t
:
(
key
:
string
)
=>
key
,
}),
}
})
vi
.
mock
(
'
@/utils/format
'
,
()
=>
({
formatDateTime
:
(
value
:
string
|
null
|
undefined
)
=>
value
??
''
,
}))
const
sampleReport
=
{
id
:
1
,
report_type
:
'
oidc_synthetic_email_requires_manual_recovery
'
,
report_key
:
'
legacy@example.invalid
'
,
details
:
{
user_id
:
42
,
legacy_email
:
'
legacy@example.invalid
'
,
provider_key
:
'
https://issuer.example
'
,
provider_subject
:
'
subject-123
'
,
},
created_at
:
'
2026-04-20T01:02:03Z
'
,
resolved_at
:
null
,
resolved_by_user_id
:
null
,
resolution_note
:
''
,
}
const
summaryResponse
=
{
total
:
2
,
open_total
:
1
,
resolved_total
:
1
,
by_type
:
{
oidc_synthetic_email_requires_manual_recovery
:
2
,
},
}
const
listResponse
=
{
items
:
[
sampleReport
],
total
:
1
,
page
:
1
,
page_size
:
20
,
pages
:
1
,
}
const
AppLayoutStub
=
defineComponent
({
setup
(
_
,
{
slots
})
{
return
()
=>
h
(
'
div
'
,
slots
.
default
?.())
},
})
const
TablePageLayoutStub
=
defineComponent
({
setup
(
_
,
{
slots
})
{
return
()
=>
h
(
'
div
'
,
[
slots
.
actions
?.(),
slots
.
filters
?.(),
slots
.
table
?.(),
slots
.
default
?.(),
slots
.
pagination
?.(),
])
},
})
const
DataTableStub
=
defineComponent
({
props
:
{
columns
:
{
type
:
Array
,
default
:
()
=>
[]
},
data
:
{
type
:
Array
,
default
:
()
=>
[]
},
loading
:
{
type
:
Boolean
,
default
:
false
},
},
setup
(
props
,
{
slots
})
{
return
()
=>
h
(
'
div
'
,
{
'
data-test
'
:
'
data-table
'
},
[
props
.
loading
?
h
(
'
div
'
,
'
loading
'
)
:
(
props
.
data
as
Array
<
Record
<
string
,
unknown
>>
).
map
((
row
)
=>
h
(
'
div
'
,
{
key
:
String
(
row
.
id
??
row
.
report_key
)
},
(
props
.
columns
as
Array
<
{
key
:
string
}
>
).
map
((
column
)
=>
{
const
slot
=
slots
[
`cell-
${
column
.
key
}
`
]
return
h
(
'
div
'
,
{
key
:
column
.
key
,
[
`data-test-cell`
]:
`
${
String
(
row
.
id
)}
-
${
column
.
key
}
`
},
slot
?
slot
({
row
,
value
:
row
[
column
.
key
]
})
:
String
(
row
[
column
.
key
]
??
''
)
)
})
)
),
])
},
})
const
PaginationStub
=
defineComponent
({
props
:
{
total
:
{
type
:
Number
,
required
:
true
},
page
:
{
type
:
Number
,
required
:
true
},
pageSize
:
{
type
:
Number
,
required
:
true
},
},
emits
:
[
'
update:page
'
,
'
update:pageSize
'
],
setup
(
props
,
{
emit
})
{
return
()
=>
h
(
'
div
'
,
{
'
data-test
'
:
'
pagination
'
},
[
h
(
'
button
'
,
{
type
:
'
button
'
,
'
data-test
'
:
'
next-page
'
,
onClick
:
()
=>
emit
(
'
update:page
'
,
props
.
page
+
1
),
},
'
next
'
),
h
(
'
button
'
,
{
type
:
'
button
'
,
'
data-test
'
:
'
page-size-50
'
,
onClick
:
()
=>
emit
(
'
update:pageSize
'
,
50
),
},
'
50
'
),
])
},
})
describe
(
'
AuthIdentityMigrationReportsView
'
,
()
=>
{
beforeEach
(()
=>
{
getAuthIdentityMigrationReportSummary
.
mockReset
()
listAuthIdentityMigrationReports
.
mockReset
()
resolveAuthIdentityMigrationReport
.
mockReset
()
bindUserAuthIdentity
.
mockReset
()
showError
.
mockReset
()
showSuccess
.
mockReset
()
getAuthIdentityMigrationReportSummary
.
mockResolvedValue
(
summaryResponse
)
listAuthIdentityMigrationReports
.
mockResolvedValue
(
listResponse
)
resolveAuthIdentityMigrationReport
.
mockResolvedValue
({
...
sampleReport
,
resolved_at
:
'
2026-04-20T02:00:00Z
'
,
resolved_by_user_id
:
100
,
resolution_note
:
'
resolved by admin
'
,
})
bindUserAuthIdentity
.
mockResolvedValue
({
identity_id
:
77
,
provider_type
:
'
oidc
'
,
provider_key
:
'
https://issuer.example
'
,
provider_subject
:
'
subject-123
'
,
})
})
const
mountView
=
()
=>
mount
(
AuthIdentityMigrationReportsView
,
{
global
:
{
stubs
:
{
AppLayout
:
AppLayoutStub
,
TablePageLayout
:
TablePageLayoutStub
,
DataTable
:
DataTableStub
,
Pagination
:
PaginationStub
,
Icon
:
true
,
},
},
})
it
(
'
loads summary and first page of reports on mount
'
,
async
()
=>
{
const
wrapper
=
mountView
()
await
flushPromises
()
expect
(
getAuthIdentityMigrationReportSummary
).
toHaveBeenCalledTimes
(
1
)
expect
(
listAuthIdentityMigrationReports
).
toHaveBeenCalledWith
({
page
:
1
,
pageSize
:
20
,
reportType
:
''
,
})
expect
(
wrapper
.
get
(
'
[data-test="summary-total"]
'
).
text
()).
toContain
(
'
2
'
)
expect
(
wrapper
.
get
(
'
[data-test="summary-open"]
'
).
text
()).
toContain
(
'
1
'
)
expect
(
wrapper
.
get
(
'
[data-test="summary-resolved"]
'
).
text
()).
toContain
(
'
1
'
)
expect
(
wrapper
.
text
()).
toContain
(
'
legacy@example.invalid
'
)
})
it
(
'
reloads list when the report type filter changes
'
,
async
()
=>
{
const
wrapper
=
mountView
()
await
flushPromises
()
listAuthIdentityMigrationReports
.
mockClear
()
await
wrapper
.
get
(
'
[data-test="report-type-filter"]
'
).
setValue
(
'
oidc_synthetic_email_requires_manual_recovery
'
)
await
flushPromises
()
expect
(
listAuthIdentityMigrationReports
).
toHaveBeenCalledWith
({
page
:
1
,
pageSize
:
20
,
reportType
:
'
oidc_synthetic_email_requires_manual_recovery
'
,
})
})
it
(
'
submits resolve note for the selected report and refreshes data
'
,
async
()
=>
{
const
wrapper
=
mountView
()
await
flushPromises
()
getAuthIdentityMigrationReportSummary
.
mockClear
()
listAuthIdentityMigrationReports
.
mockClear
()
await
wrapper
.
get
(
'
[data-test="select-report-1"]
'
).
trigger
(
'
click
'
)
await
wrapper
.
get
(
'
[data-test="resolution-note"]
'
).
setValue
(
'
resolved by admin
'
)
await
wrapper
.
get
(
'
[data-test="resolve-submit"]
'
).
trigger
(
'
click
'
)
await
flushPromises
()
expect
(
resolveAuthIdentityMigrationReport
).
toHaveBeenCalledWith
(
1
,
'
resolved by admin
'
)
expect
(
showSuccess
).
toHaveBeenCalled
()
expect
(
getAuthIdentityMigrationReportSummary
).
toHaveBeenCalledTimes
(
1
)
expect
(
listAuthIdentityMigrationReports
).
toHaveBeenCalledWith
({
page
:
1
,
pageSize
:
20
,
reportType
:
''
,
})
})
it
(
'
pre-fills and submits remediation binding for the selected report
'
,
async
()
=>
{
const
wrapper
=
mountView
()
await
flushPromises
()
await
wrapper
.
get
(
'
[data-test="select-report-1"]
'
).
trigger
(
'
click
'
)
await
flushPromises
()
expect
((
wrapper
.
get
(
'
[data-test="remediation-user-id"]
'
).
element
as
HTMLInputElement
).
value
).
toBe
(
'
42
'
)
expect
((
wrapper
.
get
(
'
[data-test="remediation-provider-type"]
'
).
element
as
HTMLInputElement
).
value
).
toBe
(
'
oidc
'
)
expect
((
wrapper
.
get
(
'
[data-test="remediation-provider-key"]
'
).
element
as
HTMLInputElement
).
value
).
toBe
(
'
https://issuer.example
'
)
expect
((
wrapper
.
get
(
'
[data-test="remediation-provider-subject"]
'
).
element
as
HTMLInputElement
).
value
).
toBe
(
'
subject-123
'
)
await
wrapper
.
get
(
'
[data-test="remediation-submit"]
'
).
trigger
(
'
click
'
)
await
flushPromises
()
expect
(
bindUserAuthIdentity
).
toHaveBeenCalledWith
(
42
,
{
provider_type
:
'
oidc
'
,
provider_key
:
'
https://issuer.example
'
,
provider_subject
:
'
subject-123
'
,
issuer
:
undefined
,
metadata
:
{},
})
expect
(
showSuccess
).
toHaveBeenCalled
()
})
it
(
'
keeps report type filter options available from list data when summary fails
'
,
async
()
=>
{
getAuthIdentityMigrationReportSummary
.
mockRejectedValueOnce
(
new
Error
(
'
summary failed
'
))
listAuthIdentityMigrationReports
.
mockResolvedValueOnce
(
listResponse
)
const
wrapper
=
mountView
()
await
flushPromises
()
const
options
=
wrapper
.
get
(
'
[data-test="report-type-filter"]
'
)
.
findAll
(
'
option
'
)
.
map
((
node
)
=>
node
.
element
.
value
)
expect
(
showError
).
toHaveBeenCalled
()
expect
(
options
).
toContain
(
'
oidc_synthetic_email_requires_manual_recovery
'
)
})
})
frontend/src/views/admin/__tests__/UsersView.spec.ts
View file @
d08757ce
...
...
@@ -70,7 +70,6 @@ const createAdminUser = (): AdminUser => ({
created_at
:
'
2026-04-17T00:00:00Z
'
,
updated_at
:
'
2026-04-17T00:00:00Z
'
,
notes
:
''
,
last_login_at
:
'
2026-04-16T01:00:00Z
'
,
last_active_at
:
'
2026-04-16T02:00:00Z
'
,
last_used_at
:
'
2026-04-17T02:00:00Z
'
,
current_concurrency
:
0
...
...
@@ -113,7 +112,7 @@ describe('admin UsersView', () => {
getBatchUserAttributes
.
mockResolvedValue
({
values
:
{}
})
})
it
(
'
shows active
and us
ed activity columns
, hides last_login_at,
and requests last_used_at sort
'
,
async
()
=>
{
it
(
'
shows active
, used, and creat
ed activity columns
in order
and requests last_used_at sort
'
,
async
()
=>
{
const
wrapper
=
mount
(
UsersView
,
{
global
:
{
stubs
:
{
...
...
@@ -145,9 +144,9 @@ describe('admin UsersView', () => {
await
flushPromises
()
const
columns
=
wrapper
.
get
(
'
[data-test="columns"]
'
).
text
()
expect
(
columns
).
toContain
(
'
last_used_at
'
)
expect
(
columns
).
toContain
(
'
last_active_at
'
)
expect
(
c
olumns
).
not
.
toContain
(
'
last_login_at
'
)
const
visibleColumns
=
columns
.
split
(
'
,
'
)
expect
(
visibleColumns
.
slice
(
-
4
,
-
1
)).
toEqual
([
'
last_active_at
'
,
'
last_used_at
'
,
'
created_at
'
]
)
expect
(
visibleC
olumns
).
not
.
toContain
(
'
last_login_at
'
)
await
wrapper
.
get
(
'
[data-test="sort-last-used"]
'
).
trigger
(
'
click
'
)
await
flushPromises
()
...
...
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