Show admin save feedback and preserve custom failover actions
This commit is contained in:
@@ -1058,6 +1058,7 @@ export function App() {
|
|||||||
onSaveUser={saveUser}
|
onSaveUser={saveUser}
|
||||||
onSetUserWalletBalance={saveUserWalletBalance}
|
onSetUserWalletBalance={saveUserWalletBalance}
|
||||||
onSaveUserGroup={saveUserGroup}
|
onSaveUserGroup={saveUserGroup}
|
||||||
|
onClearOperationMessage={() => setCoreMessage('')}
|
||||||
onSectionChange={navigateAdminSection}
|
onSectionChange={navigateAdminSection}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import type {
|
|||||||
import type { ConsoleData, StatItem } from '../app-state';
|
import type { ConsoleData, StatItem } from '../app-state';
|
||||||
import { EntityTable } from '../components/EntityTable';
|
import { EntityTable } from '../components/EntityTable';
|
||||||
import { StatGrid } from '../components/StatGrid';
|
import { StatGrid } from '../components/StatGrid';
|
||||||
import { Badge, Card, CardContent, CardHeader, CardTitle, Tabs } from '../components/ui';
|
import { Badge, Card, CardContent, CardHeader, CardTitle, ScreenMessage, Tabs } from '../components/ui';
|
||||||
import type { AdminSection, LoadState, PlatformWithModelsInput } from '../types';
|
import type { AdminSection, LoadState, PlatformWithModelsInput } from '../types';
|
||||||
import { AccessRulesPanel } from './admin/AccessRulesPanel';
|
import { AccessRulesPanel } from './admin/AccessRulesPanel';
|
||||||
import { AuditLogsPanel } from './admin/AuditLogsPanel';
|
import { AuditLogsPanel } from './admin/AuditLogsPanel';
|
||||||
@@ -76,10 +76,16 @@ export function AdminPage(props: {
|
|||||||
onSaveUser: (input: GatewayUserUpsertRequest, userId?: string) => Promise<void>;
|
onSaveUser: (input: GatewayUserUpsertRequest, userId?: string) => Promise<void>;
|
||||||
onSetUserWalletBalance: (userId: string, input: WalletBalanceAdjustmentRequest) => Promise<void>;
|
onSetUserWalletBalance: (userId: string, input: WalletBalanceAdjustmentRequest) => Promise<void>;
|
||||||
onSaveUserGroup: (input: UserGroupUpsertRequest, groupId?: string) => Promise<void>;
|
onSaveUserGroup: (input: UserGroupUpsertRequest, groupId?: string) => Promise<void>;
|
||||||
|
onClearOperationMessage: () => void;
|
||||||
onSectionChange: (value: AdminSection) => void;
|
onSectionChange: (value: AdminSection) => void;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className="pageStack">
|
<div className="pageStack">
|
||||||
|
<ScreenMessage
|
||||||
|
message={props.operationMessage}
|
||||||
|
variant={props.state === 'error' ? 'error' : 'success'}
|
||||||
|
onClose={props.onClearOperationMessage}
|
||||||
|
/>
|
||||||
<div className="subPageLayout">
|
<div className="subPageLayout">
|
||||||
<Tabs className="sideTabs" value={props.section} tabs={tabs} onValueChange={props.onSectionChange} />
|
<Tabs className="sideTabs" value={props.section} tabs={tabs} onValueChange={props.onSectionChange} />
|
||||||
<div className="subPageContent">
|
<div className="subPageContent">
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ const failoverActionDefinitions = [
|
|||||||
},
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
const failoverActionValues = new Set<string>(failoverActionDefinitions.map((item) => item.value));
|
||||||
|
|
||||||
const failoverCategoryOptions = [
|
const failoverCategoryOptions = [
|
||||||
'network',
|
'network',
|
||||||
'timeout',
|
'timeout',
|
||||||
@@ -653,19 +655,18 @@ function defaultFailoverActions(): Record<string, unknown> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function failoverCategoryRoutingGroups(allowCategories: string[], denyCategories: string[], actions: Record<string, unknown>) {
|
function failoverCategoryRoutingGroups(allowCategories: string[], denyCategories: string[], actions: Record<string, unknown>) {
|
||||||
const actionSet = new Set(failoverActionDefinitions.map((item) => item.value));
|
|
||||||
const assignments = new Map<string, string>();
|
const assignments = new Map<string, string>();
|
||||||
for (const category of cleanTags(allowCategories)) {
|
for (const category of cleanTags(allowCategories)) {
|
||||||
const rawAction = actions[category];
|
const rawAction = actions[category];
|
||||||
const action = typeof rawAction === 'string' ? rawAction : '';
|
const action = typeof rawAction === 'string' ? rawAction : '';
|
||||||
assignments.set(category, actionSet.has(action as (typeof failoverActionDefinitions)[number]['value']) ? action : 'next');
|
assignments.set(category, failoverActionValues.has(action) ? action : 'next');
|
||||||
}
|
}
|
||||||
for (const [category, rawAction] of Object.entries(actions)) {
|
for (const [category, rawAction] of Object.entries(actions)) {
|
||||||
if (assignments.has(category)) continue;
|
if (assignments.has(category)) continue;
|
||||||
const action = typeof rawAction === 'string' ? rawAction : '';
|
const action = typeof rawAction === 'string' ? rawAction : '';
|
||||||
if (action === 'stop') {
|
if (action === 'stop') {
|
||||||
assignments.set(category, 'deny');
|
assignments.set(category, 'deny');
|
||||||
} else if (actionSet.has(action as (typeof failoverActionDefinitions)[number]['value'])) {
|
} else if (failoverActionValues.has(action)) {
|
||||||
assignments.set(category, action);
|
assignments.set(category, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -708,9 +709,16 @@ function updateFailoverCategoryRouting(
|
|||||||
knownCategories.add(category);
|
knownCategories.add(category);
|
||||||
}
|
}
|
||||||
for (const [category, rawAction] of Object.entries(actions)) {
|
for (const [category, rawAction] of Object.entries(actions)) {
|
||||||
if (!knownCategories.has(category) && typeof rawAction === 'string' && rawAction !== 'next' && rawAction !== 'stop') {
|
const shouldPreserveCustomAction = (
|
||||||
nextActions[category] = rawAction;
|
!knownCategories.has(category)
|
||||||
}
|
&& typeof rawAction === 'string'
|
||||||
|
&& rawAction !== 'next'
|
||||||
|
&& rawAction !== 'stop'
|
||||||
|
&& !failoverActionValues.has(rawAction)
|
||||||
|
);
|
||||||
|
if (!shouldPreserveCustomAction) continue;
|
||||||
|
// Keep forward-compatible custom actions that this editor cannot render.
|
||||||
|
nextActions[category] = rawAction;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
allowCategories: cleanTags(nextAllowCategories),
|
allowCategories: cleanTags(nextAllowCategories),
|
||||||
|
|||||||
Reference in New Issue
Block a user