fix(oauth): align custom binding response fields in frontend (#6818)

* fix(oauth): align custom binding response fields in frontend

* fix(oauth): restore custom access policy guidance
This commit is contained in:
Seefs
2026-08-15 13:56:06 +08:00
committed by GitHub
parent 4442bb3028
commit 116255f076
14 changed files with 216 additions and 45 deletions
@@ -0,0 +1,40 @@
/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
export const ACCESS_POLICY_TEMPLATES = {
levelAndActive: `{
"logic": "and",
"conditions": [
{ "field": "trust_level", "op": "gte", "value": 2 },
{ "field": "active", "op": "eq", "value": true }
]
}`,
orgOrRole: `{
"logic": "or",
"conditions": [
{ "field": "org", "op": "eq", "value": "core" },
{ "field": "roles", "op": "contains", "value": "admin" }
]
}`,
} as const
export const ACCESS_DENIED_MESSAGE_TEMPLATES = {
level:
'Requires level {{required}}; your current level is {{current}} (field: {{field}}).',
org: 'Access is limited to approved organizations or roles. Organization: {{current.org}}; roles: {{current.roles}}.',
} as const
@@ -63,6 +63,10 @@ import {
type CustomOAuthProvider,
type CustomOAuthFormValues,
} from '../types'
import {
ACCESS_DENIED_MESSAGE_TEMPLATES,
ACCESS_POLICY_TEMPLATES,
} from './access-policy-templates'
import { DiscoveryButton } from './discovery-button'
import { PresetSelector } from './preset-selector'
@@ -603,6 +607,11 @@ export function ProviderFormDialog(props: ProviderFormDialogProps) {
render={({ field }) => (
<FormItem>
<FormLabel>{t('Access Policy (JSON)')}</FormLabel>
<FormDescription>
{t(
'Evaluate fields from the provider user info response. Conditions and nested groups use and/or logic.'
)}
</FormDescription>
<FormControl>
<JsonCodeEditor
value={field.value || ''}
@@ -618,9 +627,39 @@ export function ProviderFormDialog(props: ProviderFormDialogProps) {
</FormControl>
<FormDescription>
{t(
'JSON-based access control rules. Leave empty to allow all users.'
'Supported operators: eq, ne, gt, gte, lt, lte, in, not_in, contains, not_contains, exists, not_exists. Leave empty to allow all users.'
)}
</FormDescription>
<div className='flex flex-wrap gap-2'>
<Button
type='button'
variant='outline'
size='xs'
onClick={() =>
form.setValue(
'access_policy',
ACCESS_POLICY_TEMPLATES.levelAndActive,
{ shouldDirty: true, shouldValidate: true }
)
}
>
{t('Fill template: level and active')}
</Button>
<Button
type='button'
variant='outline'
size='xs'
onClick={() =>
form.setValue(
'access_policy',
ACCESS_POLICY_TEMPLATES.orgOrRole,
{ shouldDirty: true, shouldValidate: true }
)
}
>
{t('Fill template: organization or role')}
</Button>
</div>
<FormMessage />
</FormItem>
)}
@@ -635,11 +674,46 @@ export function ProviderFormDialog(props: ProviderFormDialogProps) {
<FormControl>
<Input
placeholder={t(
'Custom message shown when access is denied'
'e.g. Requires level {{required}}; your current level is {{current}}'
)}
{...field}
/>
</FormControl>
<FormDescription>
{t(
'Available variables: {{provider}}, {{field}}, {{op}}, {{required}}, {{current}}, and paths such as {{current.roles}}.'
)}
</FormDescription>
<div className='flex flex-wrap gap-2'>
<Button
type='button'
variant='outline'
size='xs'
onClick={() =>
form.setValue(
'access_denied_message',
ACCESS_DENIED_MESSAGE_TEMPLATES.level,
{ shouldDirty: true }
)
}
>
{t('Fill template: level message')}
</Button>
<Button
type='button'
variant='outline'
size='xs'
onClick={() =>
form.setValue(
'access_denied_message',
ACCESS_DENIED_MESSAGE_TEMPLATES.org,
{ shouldDirty: true }
)
}
>
{t('Fill template: organization message')}
</Button>
</div>
<FormMessage />
</FormItem>
)}