ui refactor

This commit is contained in:
Ishaan Jaffer 2026-02-19 18:15:44 -08:00
parent b82c7994df
commit 6cf0e7c27e
4 changed files with 289 additions and 235 deletions

View file

@ -1,29 +1,15 @@
import React, { useState, useEffect } from "react";
import { Modal, Checkbox, Button, Divider, Tag, Select, Switch, Tooltip } from "antd";
import { Modal, Checkbox, Button, Divider, Tag, Tooltip } from "antd";
import { CheckCircleOutlined, InfoCircleOutlined } from "@ant-design/icons";
import { credentialListCall } from "../networking";
import PartnerGuardrailCard from "./partner_guardrail_card";
import {
GuardrailInfo,
PartnerGuardrailConfig,
PartnerGuardrailSelection,
} from "./types";
interface GuardrailInfo {
guardrail_name: string;
description: string;
alreadyExists: boolean;
definition: any;
}
interface PartnerGuardrailConfig {
provider: string;
label: string;
description: string;
credential_provider: string;
provision_config: Record<string, any>;
}
export interface PartnerGuardrailSelection {
provider: string;
credential_name: string;
provision_config: Record<string, any>;
aws_region_name?: string;
}
export type { PartnerGuardrailSelection } from "./types";
interface GuardrailSelectionModalProps {
visible: boolean;
@ -39,181 +25,6 @@ interface GuardrailSelectionModalProps {
accessToken?: string;
}
const AWS_REGIONS = [
"us-east-1",
"us-east-2",
"us-west-2",
"eu-west-1",
"eu-west-2",
"eu-central-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-northeast-1",
];
const partnerProviderLogoMap: Record<string, string> = {
bedrock: "../ui/assets/logos/bedrock.svg",
};
const ProviderLogo: React.FC<{ provider: string }> = ({ provider }) => {
const logoSrc = partnerProviderLogoMap[provider];
if (logoSrc) {
return (
<img
src={logoSrc}
alt={provider}
style={{ height: "20px", width: "20px", objectFit: "contain" }}
onError={(e) => { e.currentTarget.style.display = "none"; }}
/>
);
}
return (
<div className="w-5 h-5 rounded bg-gray-200 flex items-center justify-center text-xs font-bold text-gray-500">
?
</div>
);
};
const ProvisionConfigTags: React.FC<{ config: Record<string, any> }> = ({ config }) => (
<div className="flex flex-wrap gap-1.5">
{config.topicPolicyConfig && (
<Tag color="orange" className="text-xs">
{config.topicPolicyConfig.topicsConfig?.length || 0} topic policy(s)
</Tag>
)}
{config.contentPolicyConfig && (
<Tag color="red" className="text-xs">
{config.contentPolicyConfig.filtersConfig?.length || 0} content filter(s)
</Tag>
)}
{config.wordPolicyConfig && (
<Tag color="purple" className="text-xs">
word policy
</Tag>
)}
{config.sensitiveInformationPolicyConfig && (
<Tag color="blue" className="text-xs">
PII detection
</Tag>
)}
</div>
);
const CredentialOption: React.FC<{
credential: any;
provider?: string;
showProviderLogo?: boolean;
}> = ({ credential, provider, showProviderLogo }) => (
<div className="flex items-center gap-2">
{showProviderLogo && provider && <ProviderLogo provider={provider} />}
<span>{credential.credential_name}</span>
{!showProviderLogo && credential.credential_info?.custom_llm_provider && (
<Tag className="text-xs">{credential.credential_info.custom_llm_provider}</Tag>
)}
</div>
);
const PartnerGuardrailCard: React.FC<{
pg: PartnerGuardrailConfig;
isEnabled: boolean;
onToggle: (checked: boolean) => void;
selectedCredential?: string;
onCredentialChange: (value: string) => void;
selectedRegion?: string;
onRegionChange: (value: string) => void;
providerCredentials: any[];
allCredentials: any[];
credentialsLoading: boolean;
}> = ({
pg,
isEnabled,
onToggle,
selectedCredential,
onCredentialChange,
selectedRegion,
onRegionChange,
providerCredentials,
allCredentials,
credentialsLoading,
}) => {
const credentialOptions = (providerCredentials.length > 0 ? providerCredentials : allCredentials).map(
(c: any) => ({
value: c.credential_name,
label: (
<CredentialOption
credential={c}
provider={pg.provider}
showProviderLogo={providerCredentials.length > 0}
/>
),
})
);
return (
<div
className={`border rounded-lg p-4 transition-colors ${
isEnabled ? "bg-orange-50 border-orange-200" : "bg-gray-50 border-gray-200"
}`}
>
<div className="flex items-start gap-3">
<div className="flex-shrink-0 pt-0.5">
<Switch size="small" checked={isEnabled} onChange={onToggle} />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<ProviderLogo provider={pg.provider} />
<span className="text-sm font-medium text-gray-900">{pg.label}</span>
</div>
<p className="text-xs text-gray-500 mb-3">{pg.description}</p>
{isEnabled && (
<div className="space-y-3 pt-2 border-t border-gray-200">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Credential
</label>
<Select
className="w-full"
size="small"
placeholder={credentialsLoading ? "Loading credentials..." : "Select a credential"}
loading={credentialsLoading}
value={selectedCredential}
onChange={onCredentialChange}
options={credentialOptions}
notFoundContent={
<div className="text-center py-2 text-gray-500 text-xs">
No credentials found. Add one in Settings &rarr; Credentials.
</div>
}
/>
</div>
{pg.provider === "bedrock" && (
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
AWS Region
</label>
<Select
className="w-full"
size="small"
placeholder="Select region (default: us-east-1)"
value={selectedRegion}
onChange={onRegionChange}
options={AWS_REGIONS.map((r) => ({ value: r, label: r }))}
allowClear
/>
</div>
)}
<ProvisionConfigTags config={pg.provision_config} />
</div>
)}
</div>
</div>
</div>
);
};
const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
visible,
template,
@ -228,23 +39,21 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
new Set()
);
// Partner guardrail state
const [partnerEnabled, setPartnerEnabled] = useState<Record<string, boolean>>(
{}
);
const [partnerEnabled, setPartnerEnabled] = useState<
Record<string, boolean>
>({});
const [partnerCredentials, setPartnerCredentials] = useState<
Record<string, string>
>({});
const [partnerRegions, setPartnerRegions] = useState<Record<string, string>>(
{}
);
const [partnerRegions, setPartnerRegions] = useState<
Record<string, string>
>({});
const [credentials, setCredentials] = useState<any[]>([]);
const [credentialsLoading, setCredentialsLoading] = useState(false);
const partnerGuardrails: PartnerGuardrailConfig[] =
const partnerGuardrailConfigs: PartnerGuardrailConfig[] =
template?.partnerGuardrails || [];
// Prepare guardrail info with existence status
const guardrailsInfo: GuardrailInfo[] = (
template?.guardrailDefinitions || []
).map((def: any) => ({
@ -254,22 +63,18 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
definition: def,
}));
// Initialize selection: select only new guardrails by default
useEffect(() => {
if (visible && template) {
const newGuardrails = guardrailsInfo
.filter((g) => !g.alreadyExists)
.map((g) => g.guardrail_name);
setSelectedGuardrails(new Set(newGuardrails));
// Reset partner state
setPartnerEnabled({});
setPartnerCredentials({});
setPartnerRegions({});
}
}, [visible, template]);
// Fetch credentials when a partner guardrail is enabled
useEffect(() => {
const anyEnabled = Object.values(partnerEnabled).some(Boolean);
if (anyEnabled && accessToken && credentials.length === 0) {
@ -315,9 +120,8 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
.filter((g) => selectedGuardrails.has(g.guardrail_name))
.map((g) => g.definition);
// Build partner guardrail selections
const partnerSelections: PartnerGuardrailSelection[] = [];
for (const pg of partnerGuardrails) {
for (const pg of partnerGuardrailConfigs) {
if (partnerEnabled[pg.provider] && partnerCredentials[pg.provider]) {
partnerSelections.push({
provider: pg.provider,
@ -334,7 +138,6 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
);
};
// Filter credentials by provider type
const getCredentialsForProvider = (credentialProvider: string) => {
return credentials.filter((c: any) => {
const provider =
@ -438,7 +241,9 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
<CheckCircleOutlined className="text-green-600 text-lg" />
) : (
<Checkbox
checked={selectedGuardrails.has(guardrail.guardrail_name)}
checked={selectedGuardrails.has(
guardrail.guardrail_name
)}
onChange={() => handleToggle(guardrail.guardrail_name)}
/>
)}
@ -457,23 +262,28 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
<p className="text-sm text-gray-600">
{guardrail.description}
</p>
{/* Show guardrail type and mode */}
<div className="flex gap-2 mt-2">
<Tag className="text-xs">
{guardrail.definition?.litellm_params?.guardrail || "unknown"}
{guardrail.definition?.litellm_params?.guardrail ||
"unknown"}
</Tag>
<Tag className="text-xs" color="blue">
{guardrail.definition?.litellm_params?.mode || "unknown"}
</Tag>
{guardrail.definition?.litellm_params?.patterns && (
<Tag className="text-xs" color="purple">
{guardrail.definition.litellm_params.patterns.length} pattern(s)
{
guardrail.definition.litellm_params.patterns.length
}{" "}
pattern(s)
</Tag>
)}
{guardrail.definition?.litellm_params?.categories && (
<Tag className="text-xs" color="orange">
{guardrail.definition.litellm_params.categories.length} category/categories
{
guardrail.definition.litellm_params.categories.length
}{" "}
category/categories
</Tag>
)}
</div>
@ -500,7 +310,8 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
<div className="flex items-center gap-2 mb-2">
<span className="text-lg"></span>
<span className="font-medium text-purple-900 text-sm">
AI-Discovered Competitors ({template.discoveredCompetitors.length})
AI-Discovered Competitors (
{template.discoveredCompetitors.length})
</span>
</div>
<div className="flex flex-wrap gap-1.5">
@ -511,14 +322,15 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
))}
</div>
<p className="text-xs text-purple-600 mt-2">
These competitor names will be automatically blocked by the competitor-name-blocker guardrail.
These competitor names will be automatically blocked by the
competitor-name-blocker guardrail.
</p>
</div>
</>
)}
{/* Partner Guardrails Section */}
{partnerGuardrails.length > 0 && (
{partnerGuardrailConfigs.length > 0 && (
<>
<Divider />
<div className="space-y-3">
@ -534,23 +346,36 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
</Tag>
</div>
{partnerGuardrails.map((pg) => (
{partnerGuardrailConfigs.map((pg) => (
<PartnerGuardrailCard
key={pg.provider}
pg={pg}
isEnabled={partnerEnabled[pg.provider] || false}
onToggle={(checked) =>
setPartnerEnabled((prev) => ({ ...prev, [pg.provider]: checked }))
setPartnerEnabled((prev) => ({
...prev,
[pg.provider]: checked,
}))
}
selectedCredential={
partnerCredentials[pg.provider] || undefined
}
selectedCredential={partnerCredentials[pg.provider] || undefined}
onCredentialChange={(value) =>
setPartnerCredentials((prev) => ({ ...prev, [pg.provider]: value }))
setPartnerCredentials((prev) => ({
...prev,
[pg.provider]: value,
}))
}
selectedRegion={partnerRegions[pg.provider] || undefined}
onRegionChange={(value) =>
setPartnerRegions((prev) => ({ ...prev, [pg.provider]: value }))
setPartnerRegions((prev) => ({
...prev,
[pg.provider]: value,
}))
}
providerCredentials={getCredentialsForProvider(pg.credential_provider)}
providerCredentials={getCredentialsForProvider(
pg.credential_provider
)}
allCredentials={credentials}
credentialsLoading={credentialsLoading}
/>
@ -565,7 +390,9 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
<div className="text-sm text-gray-600">
{selectedCount > 0 ? (
<p>
<span className="font-medium text-gray-900">{selectedCount}</span>{" "}
<span className="font-medium text-gray-900">
{selectedCount}
</span>{" "}
guardrail{selectedCount > 1 ? "s" : ""} will be created
{Object.values(partnerEnabled).some(Boolean) && (
<span className="text-orange-600">
@ -576,11 +403,13 @@ const GuardrailSelectionModal: React.FC<GuardrailSelectionModalProps> = ({
</p>
) : existingCount > 0 ? (
<p className="text-green-600">
All guardrails already exist. You can proceed to use this template.
All guardrails already exist. You can proceed to use this
template.
</p>
) : (
<p className="text-orange-600">
Select at least one guardrail to create, or click &quot;Use Template&quot; to proceed without creating new guardrails.
Select at least one guardrail to create, or click &quot;Use
Template&quot; to proceed without creating new guardrails.
</p>
)}
</div>

View file

@ -0,0 +1,186 @@
import React from "react";
import { Tag, Select, Switch } from "antd";
import {
AWS_REGIONS,
PartnerGuardrailConfig,
partnerProviderLogoMap,
} from "./types";
export const ProviderLogo: React.FC<{ provider: string }> = ({ provider }) => {
const logoSrc = partnerProviderLogoMap[provider];
if (logoSrc) {
return (
<img
src={logoSrc}
alt={provider}
style={{ height: "20px", width: "20px", objectFit: "contain" }}
onError={(e) => {
e.currentTarget.style.display = "none";
}}
/>
);
}
return (
<div className="w-5 h-5 rounded bg-gray-200 flex items-center justify-center text-xs font-bold text-gray-500">
?
</div>
);
};
const ProvisionConfigTags: React.FC<{ config: Record<string, any> }> = ({
config,
}) => (
<div className="flex flex-wrap gap-1.5">
{config.topicPolicyConfig && (
<Tag color="orange" className="text-xs">
{config.topicPolicyConfig.topicsConfig?.length || 0} topic policy(s)
</Tag>
)}
{config.contentPolicyConfig && (
<Tag color="red" className="text-xs">
{config.contentPolicyConfig.filtersConfig?.length || 0} content
filter(s)
</Tag>
)}
{config.wordPolicyConfig && (
<Tag color="purple" className="text-xs">
word policy
</Tag>
)}
{config.sensitiveInformationPolicyConfig && (
<Tag color="blue" className="text-xs">
PII detection
</Tag>
)}
</div>
);
const CredentialOption: React.FC<{
credential: any;
provider?: string;
showProviderLogo?: boolean;
}> = ({ credential, provider, showProviderLogo }) => (
<div className="flex items-center gap-2">
{showProviderLogo && provider && <ProviderLogo provider={provider} />}
<span>{credential.credential_name}</span>
{!showProviderLogo && credential.credential_info?.custom_llm_provider && (
<Tag className="text-xs">
{credential.credential_info.custom_llm_provider}
</Tag>
)}
</div>
);
export interface PartnerGuardrailCardProps {
pg: PartnerGuardrailConfig;
isEnabled: boolean;
onToggle: (checked: boolean) => void;
selectedCredential?: string;
onCredentialChange: (value: string) => void;
selectedRegion?: string;
onRegionChange: (value: string) => void;
providerCredentials: any[];
allCredentials: any[];
credentialsLoading: boolean;
}
const PartnerGuardrailCard: React.FC<PartnerGuardrailCardProps> = ({
pg,
isEnabled,
onToggle,
selectedCredential,
onCredentialChange,
selectedRegion,
onRegionChange,
providerCredentials,
allCredentials,
credentialsLoading,
}) => {
const credentialOptions = (
providerCredentials.length > 0 ? providerCredentials : allCredentials
).map((c: any) => ({
value: c.credential_name,
label: (
<CredentialOption
credential={c}
provider={pg.provider}
showProviderLogo={providerCredentials.length > 0}
/>
),
}));
return (
<div
className={`border rounded-lg p-4 transition-colors ${
isEnabled
? "bg-orange-50 border-orange-200"
: "bg-gray-50 border-gray-200"
}`}
>
<div className="flex items-start gap-3">
<div className="flex-shrink-0 pt-0.5">
<Switch size="small" checked={isEnabled} onChange={onToggle} />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<ProviderLogo provider={pg.provider} />
<span className="text-sm font-medium text-gray-900">
{pg.label}
</span>
</div>
<p className="text-xs text-gray-500 mb-3">{pg.description}</p>
{isEnabled && (
<div className="space-y-3 pt-2 border-t border-gray-200">
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
Credential
</label>
<Select
className="w-full"
size="small"
placeholder={
credentialsLoading
? "Loading credentials..."
: "Select a credential"
}
loading={credentialsLoading}
value={selectedCredential}
onChange={onCredentialChange}
options={credentialOptions}
notFoundContent={
<div className="text-center py-2 text-gray-500 text-xs">
No credentials found. Add one in Settings &rarr;
Credentials.
</div>
}
/>
</div>
{pg.provider === "bedrock" && (
<div>
<label className="block text-xs font-medium text-gray-700 mb-1">
AWS Region
</label>
<Select
className="w-full"
size="small"
placeholder="Select region (default: us-east-1)"
value={selectedRegion}
onChange={onRegionChange}
options={AWS_REGIONS.map((r) => ({ value: r, label: r }))}
allowClear
/>
</div>
)}
<ProvisionConfigTags config={pg.provision_config} />
</div>
)}
</div>
</div>
</div>
);
};
export default PartnerGuardrailCard;

View file

@ -8,6 +8,7 @@ import {
CheckCircleIcon,
} from "@heroicons/react/outline";
import { getPolicyTemplates } from "../networking";
import { partnerProviderLogoMap } from "./types";
interface PartnerGuardrailInfo {
provider: string;
@ -28,10 +29,6 @@ interface PolicyTemplateCardProps {
onUseTemplate: () => void;
}
const partnerProviderLogoMap: Record<string, string> = {
bedrock: "../ui/assets/logos/bedrock.svg",
};
const PolicyTemplateCard: React.FC<PolicyTemplateCardProps> = ({
title,
description,

View file

@ -99,3 +99,45 @@ export interface PipelineTestResult {
error_message: string | null;
modify_response_message: string | null;
}
// ---------------------------------------------------------------------------
// Guardrail selection modal types
// ---------------------------------------------------------------------------
export interface GuardrailInfo {
guardrail_name: string;
description: string;
alreadyExists: boolean;
definition: any;
}
export interface PartnerGuardrailConfig {
provider: string;
label: string;
description: string;
credential_provider: string;
provision_config: Record<string, any>;
}
export interface PartnerGuardrailSelection {
provider: string;
credential_name: string;
provision_config: Record<string, any>;
aws_region_name?: string;
}
export const AWS_REGIONS = [
"us-east-1",
"us-east-2",
"us-west-2",
"eu-west-1",
"eu-west-2",
"eu-central-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-northeast-1",
];
export const partnerProviderLogoMap: Record<string, string> = {
bedrock: "../ui/assets/logos/bedrock.svg",
};