Files
zn-ai/src/components/channels/ChannelInstructionsPanel.tsx
duanshuwen 18f12d6ce3 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.
2026-04-19 16:43:07 +08:00

69 lines
2.3 KiB
TypeScript

import { BookOpen, ExternalLink } from 'lucide-react';
import type { ChannelMeta } from '../../lib/channel-meta';
type ChannelInstructionsPanelProps = {
meta: ChannelMeta;
title: string;
viewDocsLabel: string;
};
export default function ChannelInstructionsPanel({
meta,
title,
viewDocsLabel,
}: ChannelInstructionsPanelProps) {
const canOpenDocs = Boolean(meta.docsUrl);
function openDocs(): void {
if (!meta.docsUrl) return;
try {
if (window.electron?.openExternal) {
window.electron.openExternal(meta.docsUrl);
return;
}
} catch {
// Fall back to window.open below.
}
window.open(meta.docsUrl, '_blank', 'noopener,noreferrer');
}
return (
<section className="rounded-[28px] border border-black/10 bg-[#f7f3eb] px-8 py-7 shadow-[0_10px_30px_rgba(15,23,42,0.06)] dark:border-white/10 dark:bg-[#232327]">
<div className="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div className="min-w-0">
<h3 className="text-[18px] font-semibold text-[#171717] dark:text-[#f3f4f6]">
{title}
</h3>
<p className="mt-3 max-w-3xl text-[15px] leading-7 text-[#667085] dark:text-gray-300">
{meta.description}
</p>
</div>
{canOpenDocs ? (
<button
type="button"
className="inline-flex h-12 shrink-0 items-center gap-2 rounded-full border border-black/10 bg-[#fbf8f1] px-5 text-[15px] font-semibold text-[#1f2937] transition-colors hover:bg-black/5 dark:border-white/10 dark:bg-[#2a2a2f] dark:text-gray-100 dark:hover:bg-white/10"
onClick={openDocs}
>
<BookOpen className="h-4 w-4" />
<span>{viewDocsLabel}</span>
<ExternalLink className="h-4 w-4" />
</button>
) : null}
</div>
{meta.instructions.length > 0 ? (
<ol className="mt-7 space-y-3 pl-7 text-[15px] leading-8 text-[#667085] dark:text-gray-300">
{meta.instructions.map((instruction) => (
<li key={instruction} className="list-decimal marker:font-semibold marker:text-[#4b5563] dark:marker:text-gray-300">
{instruction}
</li>
))}
</ol>
) : null}
</section>
);
}