fix: clean up profile auth binding notes
This commit is contained in:
@@ -67,23 +67,23 @@
|
||||
</p>
|
||||
|
||||
<div
|
||||
v-if="item.details && (item.details.display_name || item.details.subject_hint || bindingCountLabel(item.details) || item.details.note)"
|
||||
v-if="hasBindingDetails(item.provider, item.details)"
|
||||
class="grid gap-1 text-sm text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
<p
|
||||
v-if="item.details.display_name"
|
||||
v-if="item.provider !== 'email' && item.details?.display_name"
|
||||
class="font-medium text-gray-700 dark:text-gray-200"
|
||||
>
|
||||
{{ item.details.display_name }}
|
||||
</p>
|
||||
<p v-if="item.details.subject_hint">
|
||||
<p v-if="item.provider !== 'email' && item.details?.subject_hint">
|
||||
{{ item.details.subject_hint }}
|
||||
</p>
|
||||
<p v-if="bindingCountLabel(item.details)">
|
||||
{{ bindingCountLabel(item.details) }}
|
||||
</p>
|
||||
<p v-if="item.details.note">
|
||||
{{ item.details.note }}
|
||||
<p v-if="bindingNote(item.details)">
|
||||
{{ bindingNote(item.details) }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -298,6 +298,13 @@ const emailSubmitActionLabel = computed(() =>
|
||||
? t('profile.authBindings.confirmEmailReplaceAction')
|
||||
: t('profile.authBindings.confirmEmailBindAction')
|
||||
)
|
||||
const legacyBindingNoteKeys: Record<string, string> = {
|
||||
'Primary account email is managed from the profile form.':
|
||||
'profile.authBindings.notes.emailManagedFromProfile',
|
||||
'You can unbind this sign-in method.': 'profile.authBindings.notes.canUnbind',
|
||||
'Bind another sign-in method before unbinding.':
|
||||
'profile.authBindings.notes.bindAnotherBeforeUnbind',
|
||||
}
|
||||
|
||||
function resolveLegacyCompatibleWeChatSettings(
|
||||
settings: WeChatOAuthPublicSettings | null | undefined
|
||||
@@ -489,6 +496,36 @@ function bindingCountLabel(details: UserAuthBindingStatus | null): string {
|
||||
return t('profile.authBindings.boundCount', { count: details.bound_count })
|
||||
}
|
||||
|
||||
function bindingNote(details: UserAuthBindingStatus | null): string {
|
||||
if (!details) {
|
||||
return ''
|
||||
}
|
||||
|
||||
const noteKey = details.note_key?.trim() || legacyBindingNoteKeys[details.note?.trim() || ''] || ''
|
||||
if (noteKey) {
|
||||
const translated = t(noteKey)
|
||||
if (translated !== noteKey) {
|
||||
return translated
|
||||
}
|
||||
}
|
||||
|
||||
return details.note?.trim() || ''
|
||||
}
|
||||
|
||||
function hasBindingDetails(
|
||||
provider: UserAuthProvider,
|
||||
details: UserAuthBindingStatus | null
|
||||
): boolean {
|
||||
if (!details) {
|
||||
return false
|
||||
}
|
||||
|
||||
const showsProviderIdentityDetails =
|
||||
provider !== 'email' && Boolean(details.display_name || details.subject_hint)
|
||||
|
||||
return Boolean(showsProviderIdentityDetails || bindingCountLabel(details) || bindingNote(details))
|
||||
}
|
||||
|
||||
function toggleEmailForm(): void {
|
||||
isEmailFormExpanded.value = !isEmailFormExpanded.value
|
||||
}
|
||||
|
||||
@@ -64,6 +64,12 @@ vi.mock('vue-i18n', async (importOriginal) => {
|
||||
if (key === 'profile.authBindings.codeSentTo') return `Code sent to ${params?.email || ''}`.trim()
|
||||
if (key === 'profile.authBindings.bindSuccess') return 'Bind success'
|
||||
if (key === 'profile.authBindings.replaceSuccess') return 'Primary email updated'
|
||||
if (key === 'profile.authBindings.notes.emailManagedFromProfile')
|
||||
return 'Primary email is managed in the profile form'
|
||||
if (key === 'profile.authBindings.notes.canUnbind')
|
||||
return 'You can unbind this sign-in method'
|
||||
if (key === 'profile.authBindings.notes.bindAnotherBeforeUnbind')
|
||||
return 'Bind another sign-in method before unbinding'
|
||||
return key
|
||||
},
|
||||
}),
|
||||
@@ -164,7 +170,7 @@ describe('ProfileIdentityBindingsSection', () => {
|
||||
|
||||
await wrapper.get('[data-testid="profile-binding-wechat-action"]').trigger('click')
|
||||
|
||||
expect(locationState.current.href).toContain('/api/v1/auth/oauth/wechat/start?')
|
||||
expect(locationState.current.href).toContain('/api/v1/auth/oauth/wechat/bind/start?')
|
||||
expect(locationState.current.href).toContain('mode=open')
|
||||
expect(locationState.current.href).toContain('intent=bind_current_user')
|
||||
expect(locationState.current.href).toContain('redirect=%2Fprofile')
|
||||
@@ -219,7 +225,7 @@ describe('ProfileIdentityBindingsSection', () => {
|
||||
|
||||
await wrapper.get('[data-testid="profile-binding-wechat-action"]').trigger('click')
|
||||
|
||||
expect(locationState.current.href).toContain('/api/v1/auth/oauth/wechat/start?')
|
||||
expect(locationState.current.href).toContain('/api/v1/auth/oauth/wechat/bind/start?')
|
||||
expect(locationState.current.href).toContain('mode=open')
|
||||
expect(locationState.current.href).toContain('intent=bind_current_user')
|
||||
expect(locationState.current.href).toContain('redirect=%2Fprofile')
|
||||
@@ -401,6 +407,36 @@ describe('ProfileIdentityBindingsSection', () => {
|
||||
expect(wrapper.get('[data-testid="profile-binding-email-status"]').text()).toBe('Not bound')
|
||||
})
|
||||
|
||||
it('shows the bound email only once and localizes the email management note', () => {
|
||||
const wrapper = mount(ProfileIdentityBindingsSection, {
|
||||
global: {
|
||||
plugins: [pinia],
|
||||
},
|
||||
props: {
|
||||
user: createUser({
|
||||
email: 'alice@example.com',
|
||||
email_bound: true,
|
||||
auth_bindings: {
|
||||
email: {
|
||||
bound: true,
|
||||
display_name: 'alice@example.com',
|
||||
subject_hint: 'a***e@example.com',
|
||||
note_key: 'profile.authBindings.notes.emailManagedFromProfile',
|
||||
note: 'Primary account email is managed from the profile form.',
|
||||
} as any,
|
||||
},
|
||||
}),
|
||||
linuxdoEnabled: false,
|
||||
oidcEnabled: false,
|
||||
wechatEnabled: false,
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.text().match(/alice@example\.com/g)).toHaveLength(1)
|
||||
expect(wrapper.text()).not.toContain('a***e@example.com')
|
||||
expect(wrapper.text()).toContain('Primary email is managed in the profile form')
|
||||
})
|
||||
|
||||
it('keeps the email form available for replacing a bound primary email', async () => {
|
||||
userApiMocks.sendEmailBindingCode.mockResolvedValue(undefined)
|
||||
userApiMocks.bindEmailIdentity.mockResolvedValue(
|
||||
@@ -541,6 +577,36 @@ describe('ProfileIdentityBindingsSection', () => {
|
||||
expect(wrapper.get('[data-testid="profile-binding-linuxdo-status"]').text()).toBe('Not bound')
|
||||
})
|
||||
|
||||
it('localizes third-party unbind guidance from note_key', () => {
|
||||
const wrapper = mount(ProfileIdentityBindingsSection, {
|
||||
global: {
|
||||
plugins: [pinia],
|
||||
},
|
||||
props: {
|
||||
user: createUser({
|
||||
email_bound: true,
|
||||
linuxdo_bound: true,
|
||||
auth_bindings: {
|
||||
email: { bound: true },
|
||||
linuxdo: {
|
||||
bound: true,
|
||||
display_name: 'linuxdo-handle',
|
||||
note_key: 'profile.authBindings.notes.canUnbind',
|
||||
note: 'You can unbind this sign-in method.',
|
||||
can_unbind: true,
|
||||
} as any,
|
||||
},
|
||||
}),
|
||||
linuxdoEnabled: true,
|
||||
oidcEnabled: false,
|
||||
wechatEnabled: false,
|
||||
},
|
||||
})
|
||||
|
||||
expect(wrapper.text()).toContain('You can unbind this sign-in method')
|
||||
expect(wrapper.text()).not.toContain('You can unbind this sign-in method.')
|
||||
})
|
||||
|
||||
it('hides bind actions when provider details say bindable but the provider is disabled', () => {
|
||||
const wrapper = mount(ProfileIdentityBindingsSection, {
|
||||
global: {
|
||||
|
||||
@@ -1042,6 +1042,11 @@ export default {
|
||||
oidc: '{providerName}',
|
||||
wechat: 'WeChat',
|
||||
},
|
||||
notes: {
|
||||
emailManagedFromProfile: 'Primary email is managed in the profile form',
|
||||
canUnbind: 'You can unbind this sign-in method',
|
||||
bindAnotherBeforeUnbind: 'Bind another sign-in method before unbinding',
|
||||
},
|
||||
source: {
|
||||
avatar: 'Avatar is currently synced from {providerName}',
|
||||
username: 'Nickname is currently synced from {providerName}',
|
||||
|
||||
@@ -1046,6 +1046,11 @@ export default {
|
||||
oidc: '{providerName}',
|
||||
wechat: '微信',
|
||||
},
|
||||
notes: {
|
||||
emailManagedFromProfile: '主邮箱在资料表单中管理',
|
||||
canUnbind: '你可以解绑这个登录方式。',
|
||||
bindAnotherBeforeUnbind: '请先绑定其他登录方式,再解除当前绑定。',
|
||||
},
|
||||
source: {
|
||||
avatar: '头像当前来自 {providerName}',
|
||||
username: '昵称当前来自 {providerName}',
|
||||
|
||||
@@ -51,6 +51,7 @@ export interface UserAuthBindingStatus {
|
||||
bind_start_path?: string | null
|
||||
can_bind?: boolean
|
||||
can_unbind?: boolean
|
||||
note_key?: string | null
|
||||
note?: string | null
|
||||
metadata?: Record<string, unknown>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user