feat(teamsbot): show per-variant logs in auth test UI, single direct /v2/ test
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
ae18912e1e
commit
2f9de759eb
3 changed files with 149 additions and 36 deletions
|
|
@ -131,6 +131,7 @@ export interface AuthTestResult {
|
|||
durationMs: number;
|
||||
error?: string;
|
||||
detectedSignals: string[];
|
||||
logs: string[];
|
||||
}
|
||||
|
||||
export interface AuthTestResults {
|
||||
|
|
|
|||
|
|
@ -732,6 +732,69 @@
|
|||
max-width: 250px;
|
||||
}
|
||||
|
||||
/* Variant cell with expand toggle */
|
||||
.testVariantCell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
.testLogToggle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0.15rem;
|
||||
font-size: 0.7rem;
|
||||
color: var(--text-secondary, #666);
|
||||
border-radius: 3px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.testLogToggle:hover {
|
||||
background: var(--surface-alt, #f5f5f5);
|
||||
color: var(--primary-color, #4A90D9);
|
||||
}
|
||||
|
||||
/* Log row */
|
||||
.testLogRow td {
|
||||
padding: 0 !important;
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
.testLogContainer {
|
||||
background: var(--surface-dark, #1e1e1e);
|
||||
color: var(--text-light, #d4d4d4);
|
||||
font-family: 'Fira Code', 'Consolas', 'Courier New', monospace;
|
||||
font-size: 0.72rem;
|
||||
line-height: 1.5;
|
||||
padding: 0.5rem 0.75rem;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border-radius: 0 0 4px 4px;
|
||||
margin: 0 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
.testLogLine {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-all;
|
||||
padding: 0.05rem 0;
|
||||
}
|
||||
|
||||
.testLogInfo {
|
||||
color: var(--text-light, #d4d4d4);
|
||||
}
|
||||
|
||||
.testLogWarn {
|
||||
color: #e5a100;
|
||||
}
|
||||
|
||||
.testLogError {
|
||||
color: #f14c4c;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|||
import { useCurrentInstance } from '../../../hooks/useCurrentInstance';
|
||||
import * as teamsbotApi from '../../../api/teamsbotApi';
|
||||
import type { TeamsbotConfig, ConfigUpdateRequest, VoiceOption, AuthTestResults, AuthTestResult } from '../../../api/teamsbotApi';
|
||||
import { FaPlay, FaSpinner, FaFlask, FaImage } from 'react-icons/fa';
|
||||
import { FaPlay, FaSpinner, FaFlask, FaImage, FaChevronDown, FaChevronRight } from 'react-icons/fa';
|
||||
import styles from './Teamsbot.module.css';
|
||||
|
||||
/** Format voice name for display: "de-DE-Wavenet-A" -> "Wavenet A" + gender */
|
||||
|
|
@ -43,6 +43,7 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
const [testResults, setTestResults] = useState<AuthTestResults | null>(null);
|
||||
const [testError, setTestError] = useState<string | null>(null);
|
||||
const [screenshotPreview, setScreenshotPreview] = useState<{ src: string; caption: string } | null>(null);
|
||||
const [expandedLogs, setExpandedLogs] = useState<Set<string>>(new Set());
|
||||
|
||||
const _loadConfig = useCallback(async () => {
|
||||
if (!instanceId) return;
|
||||
|
|
@ -189,6 +190,28 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
return `${(ms / 1000).toFixed(1)}s`;
|
||||
};
|
||||
|
||||
const _toggleLogs = (variantId: string) => {
|
||||
setExpandedLogs(prev => {
|
||||
const next = new Set(prev);
|
||||
if (next.has(variantId)) {
|
||||
next.delete(variantId);
|
||||
} else {
|
||||
next.add(variantId);
|
||||
}
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const _getLogLevelClass = (log: string): string => {
|
||||
if (log.startsWith('[ERROR]') || log.startsWith('[CONSOLE:error]') || log.startsWith('[PAGE_ERROR]')) {
|
||||
return styles.testLogError;
|
||||
}
|
||||
if (log.startsWith('[WARN]') || log.startsWith('[CONSOLE:warning]')) {
|
||||
return styles.testLogWarn;
|
||||
}
|
||||
return styles.testLogInfo;
|
||||
};
|
||||
|
||||
if (loading) return <div className={styles.loading}>Lade Konfiguration...</div>;
|
||||
|
||||
return (
|
||||
|
|
@ -206,7 +229,7 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
<h4 className={styles.testSectionTitle}>Auth-Erkennung testen</h4>
|
||||
</div>
|
||||
<span className={styles.hint}>
|
||||
Testet 5 Browser-Konfigurationen gegen einen aktiven Teams-Call.
|
||||
Testet Direct-/v2/-Navigation gegen einen aktiven Teams-Call.
|
||||
Prueft ob Teams /v2/ (Auth moeglich) oder light-meetings (anonym erzwungen) liefert.
|
||||
Der Bot tritt dem Meeting NICHT bei.
|
||||
</span>
|
||||
|
|
@ -233,7 +256,7 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
{testRunning && (
|
||||
<div className={styles.testProgress}>
|
||||
<FaSpinner className={styles.spinner} />
|
||||
5 Varianten werden sequentiell getestet (~2-3 Minuten)...
|
||||
Test laeuft (~30-45 Sekunden)...
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -256,12 +279,24 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
</thead>
|
||||
<tbody>
|
||||
{testResults.variants.map((result) => (
|
||||
<tr key={result.variantId}>
|
||||
<React.Fragment key={result.variantId}>
|
||||
<tr>
|
||||
<td>
|
||||
<div className={styles.testVariantCell}>
|
||||
{result.logs && result.logs.length > 0 && (
|
||||
<button
|
||||
className={styles.testLogToggle}
|
||||
onClick={() => _toggleLogs(result.variantId)}
|
||||
title="Logs anzeigen/ausblenden"
|
||||
>
|
||||
{expandedLogs.has(result.variantId) ? <FaChevronDown /> : <FaChevronRight />}
|
||||
</button>
|
||||
)}
|
||||
<span className={styles.testVariantName}>{result.variantName}</span>
|
||||
</div>
|
||||
{result.error && (
|
||||
<div className={styles.testErrorText} title={result.error}>
|
||||
{result.error}
|
||||
{result.error.length > 120 ? result.error.substring(0, 120) + '...' : result.error}
|
||||
</div>
|
||||
)}
|
||||
</td>
|
||||
|
|
@ -290,6 +325,20 @@ export const TeamsbotSettingsView: React.FC = () => {
|
|||
)}
|
||||
</td>
|
||||
</tr>
|
||||
{expandedLogs.has(result.variantId) && result.logs && result.logs.length > 0 && (
|
||||
<tr className={styles.testLogRow}>
|
||||
<td colSpan={8}>
|
||||
<div className={styles.testLogContainer}>
|
||||
{result.logs.map((log, idx) => (
|
||||
<div key={idx} className={`${styles.testLogLine} ${_getLogLevelClass(log)}`}>
|
||||
{log}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
|
|
|||
Loading…
Reference in a new issue