fix(feishu): feishu connector name validate (#797)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
Haze
2026-04-08 19:16:15 +08:00
committed by GitHub
parent c1e165d48d
commit d03902dd4d
13 changed files with 521 additions and 17 deletions

View File

@@ -32,7 +32,11 @@ import {
type ChannelMeta,
type ChannelConfigField,
} from '@/types/channel';
import { buildQrChannelEventName, usesPluginManagedQrAccounts } from '@/lib/channel-alias';
import {
buildQrChannelEventName,
isCanonicalOpenClawAccountId,
usesPluginManagedQrAccounts,
} from '@/lib/channel-alias';
import { toast } from 'sonner';
import { useTranslation } from 'react-i18next';
import telegramIcon from '@/assets/channels/telegram.svg';
@@ -82,6 +86,7 @@ export function ChannelConfigModal({
const [configValues, setConfigValues] = useState<Record<string, string>>({});
const [channelName, setChannelName] = useState('');
const [accountIdInput, setAccountIdInput] = useState(accountId || '');
const [accountIdError, setAccountIdError] = useState<string | null>(null);
const [connecting, setConnecting] = useState(false);
const [showSecrets, setShowSecrets] = useState<Record<string, boolean>>({});
const [qrCode, setQrCode] = useState<string | null>(null);
@@ -115,6 +120,7 @@ export function ChannelConfigModal({
useEffect(() => {
setAccountIdInput(accountId || '');
setAccountIdError(null);
}, [accountId]);
useEffect(() => {
@@ -125,6 +131,7 @@ export function ChannelConfigModal({
setValidationResult(null);
setQrCode(null);
setConnecting(false);
setAccountIdError(null);
return;
}
@@ -352,16 +359,28 @@ export function ChannelConfigModal({
if (showAccountIdEditor) {
const nextAccountId = accountIdInput.trim();
if (!nextAccountId) {
toast.error(t('account.invalidId'));
const message = t('account.invalidId');
setAccountIdError(message);
toast.error(message);
setConnecting(false);
return;
}
if (!isCanonicalOpenClawAccountId(nextAccountId)) {
const message = t('account.invalidCanonicalId');
setAccountIdError(message);
toast.error(message);
setConnecting(false);
return;
}
const duplicateExists = existingAccountIds.some((id) => id === nextAccountId && id !== (accountId || '').trim());
if (duplicateExists) {
toast.error(t('account.accountIdExists', { accountId: nextAccountId }));
const message = t('account.accountIdExists', { accountId: nextAccountId });
setAccountIdError(message);
toast.error(message);
setConnecting(false);
return;
}
setAccountIdError(null);
}
if (meta.connectionType === 'qr') {
@@ -643,11 +662,20 @@ export function ChannelConfigModal({
<Input
id="account-id"
value={accountIdInput}
onChange={(event) => setAccountIdInput(event.target.value)}
onChange={(event) => {
setAccountIdInput(event.target.value);
if (accountIdError) {
setAccountIdError(null);
}
}}
placeholder={t('account.customIdPlaceholder')}
className={inputClasses}
className={cn(inputClasses, accountIdError && 'border-destructive/50 focus-visible:ring-destructive/30')}
/>
<p className="text-[12px] text-muted-foreground">{t('account.customIdHint')}</p>
{accountIdError ? (
<p className="text-[12px] text-destructive">{accountIdError}</p>
) : (
<p className="text-[12px] text-muted-foreground">{t('account.customIdHint')}</p>
)}
</div>
)}