style(MCP): Enhance dialog accessibility and styling consistency (#11585)

* style: update input IDs in BasicInfoSection for consistency and improve accessibility

* style: add border-destructive variable for improved design consistency

* style: update error border color for title input in BasicInfoSection

* style: update delete confirmation dialog title and description for MCP Server

* style: add text-destructive variable for improved design consistency

* style: update error message and border color for URL and trust fields for consistency

* style: reorder imports and update error message styling for consistency across sections

* style: enhance MCPServerDialog with copy link functionality and UI improvements

* style: enhance MCPServerDialog with improved accessibility and loading indicators

* style: bump @librechat/client to 0.4.51 and enhance OGDialogTemplate for improved selection handling

* a11y: enhance accessibility and error handling in MCPServerDialog sections

* style: enhance MCPServerDialog accessibility and improve resource name handling

* style: improve accessibility in MCPServerDialog and AuthSection, update translation for delete confirmation

* style: update aria-invalid attributes to use string values for improved accessibility in form sections

* style: enhance accessibility in AuthSection by updating aria attributes and adding error messages

* style: remove unnecessary aria-hidden attributes from Spinner components in MCPServerDialog

* style: simplify legacy selection check in OGDialogTemplate
This commit is contained in:
Marco Beretta 2026-02-12 04:08:40 +01:00 committed by GitHub
parent 299efc2ccb
commit d6b6f191f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 295 additions and 141 deletions

View file

@ -1,10 +1,10 @@
import { FormProvider } from 'react-hook-form';
import type { useMCPServerForm } from './hooks/useMCPServerForm';
import ConnectionSection from './sections/ConnectionSection';
import BasicInfoSection from './sections/BasicInfoSection';
import TransportSection from './sections/TransportSection';
import AuthSection from './sections/AuthSection';
import TrustSection from './sections/TrustSection';
import type { useMCPServerForm } from './hooks/useMCPServerForm';
import AuthSection from './sections/AuthSection';
interface MCPServerFormProps {
formHook: ReturnType<typeof useMCPServerForm>;

View file

@ -1,13 +1,18 @@
import React, { useState, useEffect } from 'react';
import { Copy, CopyCheck } from 'lucide-react';
import {
OGDialog,
OGDialogTemplate,
OGDialogContent,
OGDialogHeader,
OGDialogTitle,
Label,
Input,
Button,
TrashIcon,
Spinner,
TrashIcon,
useToastContext,
OGDialog,
OGDialogTitle,
OGDialogHeader,
OGDialogFooter,
OGDialogContent,
OGDialogTemplate,
} from '@librechat/client';
import {
SystemRoles,
@ -16,10 +21,10 @@ import {
PermissionBits,
PermissionTypes,
} from 'librechat-data-provider';
import { GenericGrantAccessDialog } from '~/components/Sharing';
import { useAuthContext, useHasAccess, useResourcePermissions, MCPServerDefinition } from '~/hooks';
import { useLocalize } from '~/hooks';
import { GenericGrantAccessDialog } from '~/components/Sharing';
import { useMCPServerForm } from './hooks/useMCPServerForm';
import { useLocalize, useCopyToClipboard } from '~/hooks';
import MCPServerForm from './MCPServerForm';
interface MCPServerDialogProps {
@ -39,8 +44,10 @@ export default function MCPServerDialog({
}: MCPServerDialogProps) {
const localize = useLocalize();
const { user } = useAuthContext();
const { showToast } = useToastContext();
// State for dialogs
const [isCopying, setIsCopying] = useState(false);
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [showRedirectUriDialog, setShowRedirectUriDialog] = useState(false);
const [createdServerId, setCreatedServerId] = useState<string | null>(null);
@ -99,20 +106,26 @@ export default function MCPServerDialog({
? `${window.location.origin}/api/mcp/${createdServerId}/oauth/callback`
: '';
const copyLink = useCopyToClipboard({ text: redirectUri });
return (
<>
{/* Delete confirmation dialog */}
<OGDialog open={showDeleteConfirm} onOpenChange={(isOpen) => setShowDeleteConfirm(isOpen)}>
<OGDialogTemplate
title={localize('com_ui_delete')}
className="max-w-[450px]"
main={<p className="text-left text-sm">{localize('com_ui_mcp_server_delete_confirm')}</p>}
selection={{
selectHandler: handleDelete,
selectClasses:
'bg-destructive text-white transition-all duration-200 hover:bg-destructive/80',
selectText: isDeleting ? <Spinner /> : localize('com_ui_delete'),
}}
title={localize('com_ui_delete_mcp_server')}
className="w-11/12 max-w-md"
description={localize('com_ui_mcp_server_delete_confirm', { 0: server?.serverName })}
selection={
<Button
onClick={handleDelete}
variant="destructive"
aria-live="polite"
aria-label={isDeleting ? localize('com_ui_deleting') : localize('com_ui_delete')}
>
{isDeleting ? <Spinner /> : localize('com_ui_delete')}
</Button>
}
/>
</OGDialog>
@ -127,48 +140,53 @@ export default function MCPServerDialog({
}
}}
>
<OGDialogContent className="w-full max-w-lg border-none bg-surface-primary text-text-primary">
<OGDialogHeader className="border-b border-border-light px-4 py-3">
<OGDialogContent showCloseButton={false} className="w-11/12 max-w-lg">
<OGDialogHeader>
<OGDialogTitle>{localize('com_ui_mcp_server_created')}</OGDialogTitle>
</OGDialogHeader>
<div className="space-y-4 p-4">
<p className="text-sm text-text-secondary">
{localize('com_ui_redirect_uri_instructions')}
</p>
<div className="rounded-lg border border-border-medium bg-surface-secondary p-3">
<label className="mb-2 block text-xs font-medium text-text-secondary">
<div className="space-y-4">
<p className="text-sm">{localize('com_ui_redirect_uri_instructions')}</p>
<div className="space-y-2">
<Label htmlFor="redirect-uri-input" className="text-sm font-medium">
{localize('com_ui_redirect_uri')}
</label>
</Label>
<div className="flex items-center gap-2">
<input
className="flex-1 rounded border border-border-medium bg-surface-primary px-3 py-2 text-sm"
value={redirectUri}
<Input
id="redirect-uri-input"
type="text"
readOnly
value={redirectUri}
className="flex-1 text-text-secondary"
/>
<Button
onClick={() => {
navigator.clipboard.writeText(redirectUri);
}}
size="icon"
variant="outline"
className="whitespace-nowrap"
onClick={() => {
if (isCopying) return;
showToast({ message: localize('com_ui_copied_to_clipboard') });
copyLink(setIsCopying);
}}
disabled={isCopying}
className="p-0"
aria-label={localize('com_ui_copy_link')}
>
{localize('com_ui_copy_link')}
{isCopying ? <CopyCheck className="size-4" /> : <Copy className="size-4" />}
</Button>
</div>
</div>
<div className="flex justify-end">
<OGDialogFooter>
<Button
variant="default"
onClick={() => {
setShowRedirectUriDialog(false);
onOpenChange(false);
setCreatedServerId(null);
}}
variant="submit"
className="text-white"
>
{localize('com_ui_done')}
</Button>
</div>
</OGDialogFooter>
</div>
</OGDialogContent>
</OGDialog>
@ -187,6 +205,7 @@ export default function MCPServerDialog({
})
: undefined
}
showCloseButton={false}
className="w-11/12 md:max-w-3xl"
main={<MCPServerForm formHook={formHook} />}
footerClassName="sm:justify-between"
@ -194,16 +213,15 @@ export default function MCPServerDialog({
isEditMode ? (
<div className="flex items-center gap-2">
<Button
type="button"
variant="outline"
variant="destructive"
size="sm"
aria-label={localize('com_ui_delete')}
aria-label={localize('com_ui_delete_mcp_server_name', {
0: server?.config?.title || server?.serverName || '',
})}
onClick={() => setShowDeleteConfirm(true)}
disabled={isSubmitting || isDeleting}
>
<div className="flex w-full items-center justify-center gap-2 text-red-500">
<TrashIcon />
</div>
<TrashIcon aria-hidden="true" />
</Button>
{shouldShowShareButton && server && (
<GenericGrantAccessDialog
@ -218,10 +236,15 @@ export default function MCPServerDialog({
buttons={
<Button
type="button"
variant="submit"
variant={isEditMode ? 'default' : 'submit'}
onClick={onSubmit}
disabled={isSubmitting}
className="text-white"
aria-live="polite"
aria-label={
isSubmitting
? localize(isEditMode ? 'com_ui_updating' : 'com_ui_creating')
: localize(isEditMode ? 'com_ui_update_mcp_server' : 'com_ui_create_mcp_server')
}
>
{isSubmitting ? (
<Spinner className="size-4" />

View file

@ -1,11 +1,11 @@
import { useMemo, useState } from 'react';
import { Copy, CopyCheck } from 'lucide-react';
import { useFormContext, useWatch } from 'react-hook-form';
import { Label, Input, Checkbox, SecretInput, Radio, useToastContext } from '@librechat/client';
import { Copy, CopyCheck } from 'lucide-react';
import { useLocalize, useCopyToClipboard } from '~/hooks';
import { cn } from '~/utils';
import { AuthTypeEnum, AuthorizationTypeEnum } from '../hooks/useMCPServerForm';
import type { MCPServerFormData } from '../hooks/useMCPServerForm';
import { useLocalize, useCopyToClipboard } from '~/hooks';
import { cn } from '~/utils';
interface AuthSectionProps {
isEditMode: boolean;
@ -62,15 +62,20 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
return (
<div className="space-y-3">
{/* Auth Type Radio */}
<div className="space-y-1.5">
<Label className="text-sm font-medium">{localize('com_ui_authentication')}</Label>
<fieldset className="space-y-1.5">
<legend>
<Label id="auth-type-label" className="text-sm font-medium">
{localize('com_ui_authentication')}
</Label>
</legend>
<Radio
options={authTypeOptions}
value={authType || AuthTypeEnum.None}
onChange={(val) => setValue('auth.auth_type', val as AuthTypeEnum)}
fullWidth
aria-labelledby="auth-type-label"
/>
</div>
</fieldset>
{/* API Key Fields */}
{authType === AuthTypeEnum.ServiceHttp && (
@ -83,9 +88,13 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
onCheckedChange={(checked) =>
setValue('auth.api_key_source', checked ? 'user' : 'admin')
}
aria-label={localize('com_ui_user_provides_key')}
aria-labelledby="user_provides_key_label"
/>
<label htmlFor="user_provides_key" className="cursor-pointer text-sm">
<label
id="user_provides_key_label"
htmlFor="user_provides_key"
className="cursor-pointer text-sm"
>
{localize('com_ui_user_provides_key')}
</label>
</div>
@ -101,8 +110,12 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
)}
{/* Header Format Radio */}
<div className="space-y-1.5">
<Label className="text-sm font-medium">{localize('com_ui_header_format')}</Label>
<fieldset className="space-y-1.5">
<legend>
<Label id="header-format-label" className="text-sm font-medium">
{localize('com_ui_header_format')}
</Label>
</legend>
<Radio
options={headerFormatOptions}
value={authorizationType || AuthorizationTypeEnum.Bearer}
@ -110,8 +123,9 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
setValue('auth.api_key_authorization_type', val as AuthorizationTypeEnum)
}
fullWidth
aria-labelledby="header-format-label"
/>
</div>
</fieldset>
{/* Custom header name */}
{authorizationType === AuthorizationTypeEnum.Custom && (
@ -137,27 +151,67 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
<div className="space-y-1.5">
<Label htmlFor="oauth_client_id" className="text-sm font-medium">
{localize('com_ui_client_id')}{' '}
{!isEditMode && <span className="text-text-secondary">*</span>}
{!isEditMode && (
<>
<span aria-hidden="true" className="text-text-secondary">
*
</span>
<span className="sr-only">{localize('com_ui_field_required')}</span>
</>
)}
</Label>
<Input
id="oauth_client_id"
autoComplete="off"
placeholder={isEditMode ? localize('com_ui_leave_blank_to_keep') : ''}
aria-invalid={errors.auth?.oauth_client_id ? 'true' : 'false'}
aria-describedby={
errors.auth?.oauth_client_id ? 'oauth-client-id-error' : undefined
}
{...register('auth.oauth_client_id', { required: !isEditMode })}
className={cn(errors.auth?.oauth_client_id && 'border-red-500')}
className={cn(errors.auth?.oauth_client_id && 'border-border-destructive')}
/>
{errors.auth?.oauth_client_id && (
<p
id="oauth-client-id-error"
role="alert"
className="text-xs text-text-destructive"
>
{localize('com_ui_field_required')}
</p>
)}
</div>
<div className="space-y-1.5">
<Label htmlFor="oauth_client_secret" className="text-sm font-medium">
{localize('com_ui_client_secret')}{' '}
{!isEditMode && <span className="text-text-secondary">*</span>}
{!isEditMode && (
<>
<span aria-hidden="true" className="text-text-secondary">
*
</span>
<span className="sr-only">{localize('com_ui_field_required')}</span>
</>
)}
</Label>
<SecretInput
id="oauth_client_secret"
placeholder={isEditMode ? localize('com_ui_leave_blank_to_keep') : ''}
aria-invalid={errors.auth?.oauth_client_secret ? 'true' : 'false'}
aria-describedby={
errors.auth?.oauth_client_secret ? 'oauth-client-secret-error' : undefined
}
{...register('auth.oauth_client_secret', { required: !isEditMode })}
className={cn(errors.auth?.oauth_client_secret && 'border-red-500')}
className={cn(errors.auth?.oauth_client_secret && 'border-border-destructive')}
/>
{errors.auth?.oauth_client_secret && (
<p
id="oauth-client-secret-error"
role="alert"
className="text-xs text-text-destructive"
>
{localize('com_ui_field_required')}
</p>
)}
</div>
</div>
@ -196,9 +250,12 @@ export default function AuthSection({ isEditMode, serverName }: AuthSectionProps
{/* Redirect URI */}
{isEditMode && redirectUri && (
<div className="space-y-1.5">
<Label className="text-sm font-medium">{localize('com_ui_redirect_uri')}</Label>
<Label htmlFor="auth-redirect-uri" className="text-sm font-medium">
{localize('com_ui_redirect_uri')}
</Label>
<div className="flex items-center gap-2">
<Input
id="auth-redirect-uri"
type="text"
readOnly
value={redirectUri}

View file

@ -1,9 +1,9 @@
import { useFormContext } from 'react-hook-form';
import { Input, Label, TextareaAutosize } from '@librechat/client';
import { Input, Label, Textarea } from '@librechat/client';
import type { MCPServerFormData } from '../hooks/useMCPServerForm';
import MCPIcon from '~/components/SidePanel/Agents/MCPIcon';
import { useLocalize } from '~/hooks';
import { cn } from '~/utils';
import MCPIcon from '~/components/SidePanel/Agents/MCPIcon';
import type { MCPServerFormData } from '../hooks/useMCPServerForm';
export default function BasicInfoSection() {
const localize = useLocalize();
@ -36,13 +36,19 @@ export default function BasicInfoSection() {
<MCPIcon icon={iconValue} onIconChange={handleIconChange} />
</div>
<div className="w-full space-y-1.5 sm:flex-1">
<Label htmlFor="title" className="text-sm font-medium">
{localize('com_ui_name')} <span className="text-text-secondary">*</span>
<Label htmlFor="mcp-title" className="text-sm font-medium">
{localize('com_ui_name')}{' '}
<span aria-hidden="true" className="text-text-secondary">
*
</span>
<span className="sr-only">{localize('com_ui_field_required')}</span>
</Label>
<Input
id="title"
id="mcp-title"
autoComplete="off"
placeholder={localize('com_agents_mcp_name_placeholder')}
aria-invalid={errors.title ? 'true' : 'false'}
aria-describedby={errors.title ? 'mcp-title-error' : undefined}
{...register('title', {
required: localize('com_ui_field_required'),
pattern: {
@ -50,26 +56,26 @@ export default function BasicInfoSection() {
message: localize('com_ui_mcp_title_invalid'),
},
})}
className={cn(errors.title && 'border-red-500 focus:border-red-500')}
className={cn(errors.title && 'border-border-destructive')}
/>
{errors.title && <p className="text-xs text-red-500">{errors.title.message}</p>}
{errors.title && (
<p id="mcp-title-error" role="alert" className="text-xs text-text-destructive">
{errors.title.message}
</p>
)}
</div>
</div>
{/* Description - always visible, full width */}
{/* Description */}
<div className="space-y-1.5">
<Label htmlFor="description" className="text-sm font-medium">
<Label htmlFor="mcp-description" className="text-sm font-medium">
{localize('com_ui_description')}{' '}
<span className="text-xs text-text-secondary">{localize('com_ui_optional')}</span>
</Label>
<TextareaAutosize
id="description"
aria-label={localize('com_ui_description')}
<Textarea
id="mcp-description"
placeholder={localize('com_agents_mcp_description_placeholder')}
{...register('description')}
minRows={2}
maxRows={4}
className="w-full resize-none rounded-lg border border-input bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none"
/>
</div>
</div>

View file

@ -15,13 +15,19 @@ export default function ConnectionSection() {
return (
<div className="space-y-1.5">
<Label htmlFor="url" className="text-sm font-medium">
{localize('com_ui_mcp_url')} <span className="text-text-secondary">*</span>
{localize('com_ui_mcp_url')}{' '}
<span aria-hidden="true" className="text-text-secondary">
*
</span>
<span className="sr-only">{localize('com_ui_field_required')}</span>
</Label>
<Input
id="url"
type="url"
autoComplete="off"
placeholder={localize('com_ui_mcp_server_url_placeholder')}
aria-invalid={errors.url ? 'true' : 'false'}
aria-describedby={errors.url ? 'url-error' : undefined}
{...register('url', {
required: localize('com_ui_field_required'),
validate: (value) => {
@ -29,9 +35,13 @@ export default function ConnectionSection() {
return isValidUrl(normalized) || localize('com_ui_mcp_invalid_url');
},
})}
className={cn(errors.url && 'border-red-500 focus:border-red-500')}
className={cn(errors.url && 'border-border-destructive')}
/>
{errors.url && <p className="text-xs text-red-500">{errors.url.message}</p>}
{errors.url && (
<p id="url-error" role="alert" className="text-xs text-text-destructive">
{errors.url.message}
</p>
)}
</div>
);
}

View file

@ -25,14 +25,19 @@ export default function TransportSection() {
);
return (
<div className="space-y-2">
<Label className="text-sm font-medium">{localize('com_ui_mcp_transport')}</Label>
<fieldset className="space-y-2">
<legend>
<Label id="transport-label" className="text-sm font-medium">
{localize('com_ui_mcp_transport')}
</Label>
</legend>
<Radio
options={transportOptions}
value={transportType}
onChange={handleTransportChange}
fullWidth
aria-labelledby="transport-label"
/>
</div>
</fieldset>
);
}

View file

@ -26,17 +26,17 @@ export default function TrustSection() {
checked={field.value}
onCheckedChange={field.onChange}
aria-labelledby="trust-label"
aria-describedby="trust-description"
aria-describedby={
errors.trust ? 'trust-description trust-error' : 'trust-description'
}
aria-invalid={errors.trust ? 'true' : 'false'}
aria-required="true"
className="mt-0.5"
/>
)}
/>
<Label
id="trust-label"
htmlFor="trust"
className="flex cursor-pointer flex-col gap-0.5 text-sm"
>
<span className="font-medium text-text-primary">
<Label htmlFor="trust" className="flex cursor-pointer flex-col gap-0.5 text-sm">
<span id="trust-label" className="font-medium text-text-primary">
{startupConfig?.interface?.mcpServers?.trustCheckbox?.label ? (
<span
dangerouslySetInnerHTML={{
@ -49,7 +49,9 @@ export default function TrustSection() {
) : (
localize('com_ui_trust_app')
)}{' '}
<span className="text-text-secondary">*</span>
<span aria-hidden="true" className="text-text-secondary">
*
</span>
</span>
<span id="trust-description" className="text-xs font-normal text-text-secondary">
{startupConfig?.interface?.mcpServers?.trustCheckbox?.subLabel ? (
@ -68,7 +70,9 @@ export default function TrustSection() {
</Label>
</div>
{errors.trust && (
<p className="mt-2 text-xs text-red-500">{localize('com_ui_field_required')}</p>
<p id="trust-error" role="alert" className="mt-2 text-xs text-text-destructive">
{localize('com_ui_field_required')}
</p>
)}
</div>
);

View file

@ -857,8 +857,11 @@
"com_ui_copy_url_to_clipboard": "Copy URL to clipboard",
"com_ui_create": "Create",
"com_ui_create_api_key": "Create API Key",
"com_ui_created": "Created",
"com_ui_creating": "Creating...",
"com_ui_create_assistant": "Create Assistant",
"com_ui_create_link": "Create link",
"com_ui_create_mcp_server": "Create MCP server",
"com_ui_create_memory": "Create Memory",
"com_ui_create_new_agent": "Create New Agent",
"com_ui_create_prompt": "Create Prompt",
@ -893,6 +896,7 @@
"com_ui_decline": "I do not accept",
"com_ui_default_post_request": "Default (POST request)",
"com_ui_delete": "Delete",
"com_ui_deleting": "Deleting...",
"com_ui_delete_action": "Delete Action",
"com_ui_delete_action_confirm": "Are you sure you want to delete this action?",
"com_ui_delete_agent": "Delete Agent",
@ -915,6 +919,8 @@
"com_ui_delete_tool": "Delete Tool",
"com_ui_delete_tool_confirm": "Are you sure you want to delete this tool?",
"com_ui_delete_tool_save_reminder": "Tool removed. Save the agent to apply changes.",
"com_ui_delete_mcp_server": "Delete MCP Server?",
"com_ui_delete_mcp_server_name": "Delete MCP server {{0}}",
"com_ui_deleted": "Deleted",
"com_ui_deleting_file": "Deleting file...",
"com_ui_descending": "Desc",
@ -1111,7 +1117,7 @@
"com_ui_mcp_server": "MCP Server",
"com_ui_mcp_server_connection_failed": "Connection attempt to the provided MCP server failed. Please make sure the URL, the server type, and any authentication configuration are correct, then try again. Also ensure the URL is reachable.",
"com_ui_mcp_server_created": "MCP server created successfully",
"com_ui_mcp_server_delete_confirm": "Are you sure you want to delete this MCP server?",
"com_ui_mcp_server_delete_confirm": "Are you sure you want to delete the {{0}} MCP server?",
"com_ui_mcp_server_deleted": "MCP server deleted successfully",
"com_ui_mcp_server_role_editor": "MCP Server Editor",
"com_ui_mcp_server_role_editor_desc": "Can view, use, and edit MCP servers",
@ -1438,6 +1444,8 @@
"com_ui_unset": "Unset",
"com_ui_untitled": "Untitled",
"com_ui_update": "Update",
"com_ui_updating": "Updating...",
"com_ui_update_mcp_server": "Update MCP server",
"com_ui_upload": "Upload",
"com_ui_upload_agent_avatar": "Successfully updated agent avatar",
"com_ui_upload_agent_avatar_label": "Upload agent avatar image",

View file

@ -70,6 +70,7 @@ html {
--text-secondary-alt: var(--gray-500);
--text-tertiary: var(--gray-500);
--text-warning: var(--amber-500);
--text-destructive: var(--red-600);
--ring-primary: var(--gray-500);
--header-primary: var(--white);
--header-hover: var(--gray-50);
@ -96,6 +97,7 @@ html {
--border-medium: var(--gray-300);
--border-heavy: var(--gray-400);
--border-xheavy: var(--gray-500);
--border-destructive: var(--red-600);
/* These are test styles */
--background: 0 0% 100%;
@ -131,6 +133,7 @@ html {
--text-secondary-alt: var(--gray-400);
--text-tertiary: var(--gray-500);
--text-warning: var(--amber-500);
--text-destructive: var(--red-600);
--header-primary: var(--gray-700);
--header-hover: var(--gray-600);
--header-button-hover: var(--gray-700);
@ -156,6 +159,7 @@ html {
--border-medium: var(--gray-600);
--border-heavy: var(--gray-500);
--border-xheavy: var(--gray-400);
--border-destructive: var(--red-500);
/* These are test styles */
--background: 0 0% 7%;

View file

@ -19,10 +19,10 @@ export const RESOURCE_CONFIGS: Record<ResourceType, ResourceConfig> = {
defaultEditorRoleId: AccessRoleIds.AGENT_EDITOR,
defaultOwnerRoleId: AccessRoleIds.AGENT_OWNER,
getResourceUrl: (agentId: string) => `${window.location.origin}/c/new?agent_id=${agentId}`,
getResourceName: (name?: string) => (name && name !== '' ? `"${name}"` : 'agent'),
getShareMessage: (name?: string) => (name && name !== '' ? `"${name}"` : 'agent'),
getResourceName: (name?: string) => (name && name !== '' ? name : 'agent'),
getShareMessage: (name?: string) => (name && name !== '' ? name : 'agent'),
getManageMessage: (name?: string) =>
`Manage permissions for ${name && name !== '' ? `"${name}"` : 'agent'}`,
`Manage permissions for ${name && name !== '' ? name : 'agent'}`,
getCopyUrlMessage: () => 'Agent URL copied',
},
[ResourceType.PROMPTGROUP]: {
@ -30,10 +30,10 @@ export const RESOURCE_CONFIGS: Record<ResourceType, ResourceConfig> = {
defaultViewerRoleId: AccessRoleIds.PROMPTGROUP_VIEWER,
defaultEditorRoleId: AccessRoleIds.PROMPTGROUP_EDITOR,
defaultOwnerRoleId: AccessRoleIds.PROMPTGROUP_OWNER,
getResourceName: (name?: string) => (name && name !== '' ? `"${name}"` : 'prompt'),
getShareMessage: (name?: string) => (name && name !== '' ? `"${name}"` : 'prompt'),
getResourceName: (name?: string) => (name && name !== '' ? name : 'prompt'),
getShareMessage: (name?: string) => (name && name !== '' ? name : 'prompt'),
getManageMessage: (name?: string) =>
`Manage permissions for ${name && name !== '' ? `"${name}"` : 'prompt'}`,
`Manage permissions for ${name && name !== '' ? name : 'prompt'}`,
getCopyUrlMessage: () => 'Prompt URL copied',
},
[ResourceType.MCPSERVER]: {
@ -41,10 +41,10 @@ export const RESOURCE_CONFIGS: Record<ResourceType, ResourceConfig> = {
defaultViewerRoleId: AccessRoleIds.MCPSERVER_VIEWER,
defaultEditorRoleId: AccessRoleIds.MCPSERVER_EDITOR,
defaultOwnerRoleId: AccessRoleIds.MCPSERVER_OWNER,
getResourceName: (name?: string) => (name && name !== '' ? `"${name}"` : 'MCP server'),
getShareMessage: (name?: string) => (name && name !== '' ? `"${name}"` : 'MCP server'),
getResourceName: (name?: string) => (name && name !== '' ? name : 'MCP server'),
getShareMessage: (name?: string) => (name && name !== '' ? name : 'MCP server'),
getManageMessage: (name?: string) =>
`Manage permissions for ${name && name !== '' ? `"${name}"` : 'MCP server'}`,
`Manage permissions for ${name && name !== '' ? name : 'MCP server'}`,
getCopyUrlMessage: () => 'MCP Server URL copied',
},
[ResourceType.REMOTE_AGENT]: {

View file

@ -92,6 +92,7 @@ module.exports = {
'text-secondary-alt': 'var(--text-secondary-alt)',
'text-tertiary': 'var(--text-tertiary)',
'text-warning': 'var(--text-warning)',
'text-destructive': 'var(--text-destructive)',
'ring-primary': 'var(--ring-primary)',
'header-primary': 'var(--header-primary)',
'header-hover': 'var(--header-hover)',
@ -118,6 +119,7 @@ module.exports = {
'border-medium-alt': 'var(--border-medium-alt)',
'border-heavy': 'var(--border-heavy)',
'border-xheavy': 'var(--border-xheavy)',
'border-destructive': 'var(--border-destructive)',
/* These are test styles */
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',