feat: enhance channel configuration UI and validation

- Updated ChannelInstructionsPanel to include a button for viewing documentation, improving user guidance.
- Enhanced ChannelTokenField to support showing/hiding secret values with appropriate labels and icons.
- Refined ChannelTypeSelector to display connection type icons and improved layout for better user experience.
- Added new messages for documentation links, validation feedback, and secret management in i18n.
- Extended ChannelMeta to include optional documentation URLs for better context on configuration fields.
- Implemented credential validation logic in ChannelsPage to ensure user inputs are validated before saving.
- Introduced ChannelLogo component to display channel icons in the UI.
- Added tests for channel credential validation to ensure proper error handling and feedback.
This commit is contained in:
duanshuwen
2026-04-19 16:43:07 +08:00
parent d2e48b21d8
commit 18f12d6ce3
22 changed files with 1131 additions and 301 deletions

View File

@@ -1,38 +1,66 @@
import { Check, Loader2, ShieldCheck } from 'lucide-react';
type ChannelConfigActionsProps = {
cancelLabel: string;
confirmLabel: string;
onClose: () => void;
validateLabel?: string;
validatingLabel?: string;
onConfirm: () => void;
onValidate?: () => void;
disabled?: boolean;
submitting?: boolean;
validating?: boolean;
};
export default function ChannelConfigActions({
cancelLabel,
confirmLabel,
onClose,
validateLabel,
validatingLabel,
onConfirm,
onValidate,
disabled,
submitting,
validating,
}: ChannelConfigActionsProps) {
return (
<div className="flex items-center justify-end gap-3 pt-1">
<button
type="button"
className="h-[40px] rounded-full bg-[#EDECE4] px-5 text-[13px] font-semibold text-[#4B4B4B] transition-colors hover:bg-[#E5E4DC] disabled:cursor-not-allowed disabled:opacity-60 dark:bg-[#222225] dark:text-gray-200"
onClick={onClose}
disabled={disabled || submitting}
>
{cancelLabel}
</button>
<div className="flex flex-col gap-3 border-t border-black/10 pt-6 sm:flex-row sm:justify-end dark:border-white/10">
{onValidate ? (
<button
type="button"
className="inline-flex h-[54px] items-center justify-center rounded-full border border-black/10 bg-[#fbf8f1] px-6 text-[15px] font-semibold text-[#1f2937] transition-colors hover:bg-black/5 disabled:cursor-not-allowed disabled:opacity-60 dark:border-white/10 dark:bg-[#1a1a1e] dark:text-gray-100 dark:hover:bg-white/10"
onClick={onValidate}
disabled={disabled || submitting || validating}
>
{validating ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{validatingLabel ?? validateLabel}
</>
) : (
<>
<ShieldCheck className="mr-2 h-4 w-4" />
{validateLabel}
</>
)}
</button>
) : null}
<button
type="button"
className="h-[40px] rounded-full bg-[#2B7FFF] px-5 text-[13px] font-semibold text-white transition-opacity hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-60"
className="inline-flex h-[54px] items-center justify-center rounded-full bg-[#8ea8ff] px-7 text-[15px] font-semibold text-white transition-colors hover:bg-[#7f9afb] disabled:cursor-not-allowed disabled:opacity-60 dark:bg-[#8ea8ff] dark:text-white dark:hover:bg-[#7f9afb]"
onClick={onConfirm}
disabled={disabled || submitting}
disabled={disabled || submitting || validating}
>
{submitting ? `${confirmLabel}...` : confirmLabel}
{submitting ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{confirmLabel}...
</>
) : (
<>
<Check className="mr-2 h-4 w-4" />
{confirmLabel}
</>
)}
</button>
</div>
);