mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 10:27:46 +08:00
feat(usage): enrich audit metadata and detail views
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import {
|
||||
buildApiKeyRedactionFeatureSettingsPatch,
|
||||
resolveApiKeyRedactionFormState,
|
||||
} from '../apiKeyFeatureSettings'
|
||||
|
||||
const redaction = {
|
||||
enabled: true,
|
||||
inject_model_instruction: false,
|
||||
}
|
||||
|
||||
describe('managed API key feature setting inheritance', () => {
|
||||
it('uses the target user value for an inherited key form', () => {
|
||||
expect(resolveApiKeyRedactionFormState(null, {
|
||||
chat_pii_redaction: redaction,
|
||||
})).toEqual({
|
||||
mode: 'inherit',
|
||||
...redaction,
|
||||
})
|
||||
})
|
||||
|
||||
it('omits feature_settings when a created key keeps inheritance', () => {
|
||||
expect(buildApiKeyRedactionFeatureSettingsPatch({
|
||||
isEditing: false,
|
||||
currentFeatureSettings: undefined,
|
||||
mode: 'inherit',
|
||||
value: redaction,
|
||||
})).toEqual({})
|
||||
})
|
||||
|
||||
it('writes an override only when custom mode is selected', () => {
|
||||
expect(buildApiKeyRedactionFeatureSettingsPatch({
|
||||
isEditing: false,
|
||||
currentFeatureSettings: undefined,
|
||||
mode: 'custom',
|
||||
value: redaction,
|
||||
})).toEqual({
|
||||
feature_settings: {
|
||||
chat_pii_redaction: redaction,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('does not create an override when only another field of an inherited key changes', () => {
|
||||
expect(buildApiKeyRedactionFeatureSettingsPatch({
|
||||
isEditing: true,
|
||||
currentFeatureSettings: null,
|
||||
mode: 'inherit',
|
||||
value: redaction,
|
||||
})).toEqual({})
|
||||
})
|
||||
|
||||
it('removes only the existing redaction override when inheritance is restored', () => {
|
||||
expect(buildApiKeyRedactionFeatureSettingsPatch({
|
||||
isEditing: true,
|
||||
currentFeatureSettings: {
|
||||
chat_pii_redaction: { enabled: false },
|
||||
notification_push_service: { enabled: true },
|
||||
},
|
||||
mode: 'inherit',
|
||||
value: redaction,
|
||||
})).toEqual({
|
||||
feature_settings: {
|
||||
notification_push_service: { enabled: true },
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,64 @@
|
||||
import type { FeatureSettings } from '@/api/users'
|
||||
import {
|
||||
hasChatPiiRedactionFeatureSettings,
|
||||
mergeChatPiiRedactionFeatureSettings,
|
||||
readChatPiiRedactionFeatureSettings,
|
||||
removeChatPiiRedactionFeatureSettings,
|
||||
type ChatPiiRedactionFeatureSettings,
|
||||
} from '@/utils/featureSettings'
|
||||
|
||||
export type ApiKeyRedactionMode = 'inherit' | 'custom'
|
||||
|
||||
export interface ApiKeyRedactionFormState extends ChatPiiRedactionFeatureSettings {
|
||||
mode: ApiKeyRedactionMode
|
||||
}
|
||||
|
||||
export function resolveApiKeyRedactionFormState(
|
||||
apiKeyFeatureSettings: FeatureSettings | null | undefined,
|
||||
inheritedUserFeatureSettings: FeatureSettings | null | undefined,
|
||||
): ApiKeyRedactionFormState {
|
||||
const hasCustomRedaction = hasChatPiiRedactionFeatureSettings(apiKeyFeatureSettings)
|
||||
const value = readChatPiiRedactionFeatureSettings(
|
||||
hasCustomRedaction ? apiKeyFeatureSettings : inheritedUserFeatureSettings,
|
||||
)
|
||||
return {
|
||||
mode: hasCustomRedaction ? 'custom' : 'inherit',
|
||||
...value,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds only the feature-settings portion of an API-key mutation.
|
||||
*
|
||||
* An omitted field preserves inheritance. `null` (or an object with the
|
||||
* redaction key removed) is emitted only when an existing custom override is
|
||||
* explicitly switched back to inheritance.
|
||||
*/
|
||||
export function buildApiKeyRedactionFeatureSettingsPatch(options: {
|
||||
isEditing: boolean
|
||||
currentFeatureSettings: FeatureSettings | null | undefined
|
||||
mode: ApiKeyRedactionMode
|
||||
value: ChatPiiRedactionFeatureSettings
|
||||
}): { feature_settings?: FeatureSettings | null } {
|
||||
if (options.mode === 'custom') {
|
||||
return {
|
||||
feature_settings: mergeChatPiiRedactionFeatureSettings(
|
||||
options.isEditing ? options.currentFeatureSettings : null,
|
||||
options.value,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
options.isEditing
|
||||
&& hasChatPiiRedactionFeatureSettings(options.currentFeatureSettings)
|
||||
) {
|
||||
return {
|
||||
feature_settings: removeChatPiiRedactionFeatureSettings(
|
||||
options.currentFeatureSettings,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
return {}
|
||||
}
|
||||
@@ -104,15 +104,47 @@
|
||||
|
||||
<div class="space-y-3 rounded-lg border border-border bg-muted/30 p-3">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div>
|
||||
<Label class="text-sm font-medium">
|
||||
{{ legacyT('敏感信息保护') }}
|
||||
</Label>
|
||||
<p class="mt-1 text-xs text-muted-foreground">
|
||||
{{ legacyT(form.chat_pii_redaction_mode === 'inherit' ? '跟随目标用户设置' : '仅覆盖此 API Key') }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="form.chat_pii_redaction_mode === 'inherit' ? 'default' : 'outline'"
|
||||
@click="updateField('chat_pii_redaction_mode', 'inherit')"
|
||||
>
|
||||
{{ legacyT('跟随用户') }}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
:variant="form.chat_pii_redaction_mode === 'custom' ? 'default' : 'outline'"
|
||||
@click="updateField('chat_pii_redaction_mode', 'custom')"
|
||||
>
|
||||
{{ legacyT('单独配置') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="form.chat_pii_redaction_mode === 'custom'"
|
||||
class="flex items-center justify-between gap-3 border-t border-border/50 pt-3"
|
||||
>
|
||||
<Label class="text-sm font-medium">
|
||||
{{ legacyT('敏感信息保护') }}
|
||||
{{ legacyT('启用保护') }}
|
||||
</Label>
|
||||
<Switch
|
||||
:model-value="form.chat_pii_redaction_enabled"
|
||||
@update:model-value="updateField('chat_pii_redaction_enabled', $event)"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div
|
||||
v-if="form.chat_pii_redaction_mode === 'custom' && form.chat_pii_redaction_enabled"
|
||||
class="flex items-center justify-between gap-3 border-t border-border/50 pt-3"
|
||||
>
|
||||
<Label class="text-sm font-medium">
|
||||
{{ legacyT('占位符说明') }}
|
||||
</Label>
|
||||
@@ -156,6 +188,7 @@ export interface UserApiKeyFormState {
|
||||
rate_limit?: number
|
||||
concurrent_limit?: number
|
||||
ip_rules_text: string
|
||||
chat_pii_redaction_mode: 'inherit' | 'custom'
|
||||
chat_pii_redaction_enabled: boolean
|
||||
chat_pii_redaction_placeholder_notice: boolean
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user