refactor: clean up TeamProvisioningService and enhance TaskCommentsSection UI

- Removed outdated OAuth token warning logic from TeamProvisioningService to streamline authentication handling.
- Updated TeamProvisioningBanner to prevent auto-dismissal of "ready" state, allowing users to inspect logs after rapid provisioning cycles.
- Enhanced TaskCommentsSection UI by integrating MemberBadge for author display and improving comment styling for better visual clarity.

Made-with: Cursor
This commit is contained in:
iliya 2026-03-03 16:46:14 +02:00
parent 16bb2c0b63
commit 0e627c4b3f
3 changed files with 40 additions and 62 deletions

View file

@ -957,17 +957,6 @@ export class TeamProvisioningService {
'Using ANTHROPIC_AUTH_TOKEN (proxy) mapped to ANTHROPIC_API_KEY for `-p` mode.'
);
}
if (authSource === 'claude_code_oauth_token_credentials') {
const source =
process.platform === 'darwin'
? 'macOS Keychain or credentials file'
: `${path.join(getClaudeBasePath(), '.credentials.json')}`;
warnings.push(
`Using OAuth token from ${source}. ` +
'Note: this token may be stale if Claude Code refreshed it in-memory without persisting. ' +
'If auth fails, run `claude setup-token` and export CLAUDE_CODE_OAUTH_TOKEN.'
);
}
const probe = await this.probeClaudeRuntime(claudePath, targetCwd, executionEnv);

View file

@ -26,8 +26,6 @@ function findProgressForTeam(
return matching[0] ?? null;
}
const READY_DISMISS_MS = 5_000;
export const TeamProvisioningBanner = ({
teamName,
}: TeamProvisioningBannerProps): React.JSX.Element | null => {
@ -49,28 +47,9 @@ export const TeamProvisioningBanner = ({
}
}
useEffect(() => {
if (progress?.state !== 'ready') {
return;
}
// If we captured any logs/output, keep the banner visible so the user
// can inspect what happened (common for fast stop→start cycles).
if (progress.assistantOutput || progress.cliLogsTail || progress.error) {
return;
}
const timer = window.setTimeout(() => {
setDismissed(true);
}, READY_DISMISS_MS);
return () => {
window.clearTimeout(timer);
};
}, [
progress?.state,
progress?.runId,
progress?.assistantOutput,
progress?.cliLogsTail,
progress?.error,
]);
// NOTE: we intentionally do NOT auto-dismiss "ready" banners.
// Users frequently need to inspect launch output after fast stop→start cycles,
// and auto-dismiss can make it look like no progress/logs were produced.
if (!progress || dismissed) {
return null;

View file

@ -2,9 +2,9 @@ import { useCallback, useMemo, useState } from 'react';
import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer';
import { ReplyQuoteBlock } from '@renderer/components/team/activity/ReplyQuoteBlock';
import { MemberBadge } from '@renderer/components/team/MemberBadge';
import { MentionableTextarea } from '@renderer/components/ui/MentionableTextarea';
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
import { getTeamColorSet } from '@renderer/constants/teamColors';
import { useDraftPersistence } from '@renderer/hooks/useDraftPersistence';
import { useMarkCommentsRead } from '@renderer/hooks/useMarkCommentsRead';
import { useStore } from '@renderer/store';
@ -14,7 +14,16 @@ import { getModifierKeyName } from '@renderer/utils/keyboardUtils';
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
import { formatDistanceToNow } from 'date-fns';
import { ChevronDown, ChevronUp, MessageSquare, Reply, Send, X } from 'lucide-react';
import {
CheckCircle2,
ChevronDown,
ChevronUp,
Eye,
MessageSquare,
Reply,
Send,
X,
} from 'lucide-react';
import type { MentionSuggestion } from '@renderer/types/mention';
import type { ResolvedTeamMember, TaskComment } from '@shared/types';
@ -146,19 +155,30 @@ export const TaskCommentsSection = ({
) : null}
{visibleComments.map((comment) => (
<div key={comment.id} className="group p-2.5">
<div
key={comment.id}
className={[
'group rounded-md p-2.5',
comment.type === 'review_approved'
? 'border border-emerald-500/20 bg-emerald-500/5'
: comment.type === 'review_request'
? 'border border-blue-500/20 bg-blue-500/5'
: '',
].join(' ')}
>
<div className="mb-1 flex items-center gap-2 text-[10px] text-[var(--color-text-muted)]">
<span
className="font-medium"
style={{
color: (() => {
const rc = colorMap.get(comment.author);
return rc ? getTeamColorSet(rc).text : 'var(--color-text-secondary)';
})(),
}}
>
{comment.author}
</span>
<MemberBadge name={comment.author} color={colorMap.get(comment.author)} />
{comment.type === 'review_approved' ? (
<span className="inline-flex items-center gap-0.5 rounded-full bg-emerald-500/15 px-1.5 py-0.5 text-[10px] font-medium text-emerald-400">
<CheckCircle2 size={10} />
Approved
</span>
) : comment.type === 'review_request' ? (
<span className="inline-flex items-center gap-0.5 rounded-full bg-blue-500/15 px-1.5 py-0.5 text-[10px] font-medium text-blue-400">
<Eye size={10} />
Review requested
</span>
) : null}
<span>
{(() => {
const date = new Date(comment.createdAt);
@ -290,19 +310,9 @@ export const TaskCommentsSection = ({
{replyTo ? (
<div className="mb-2 flex items-start gap-2 rounded-md border border-[var(--color-border)] bg-[var(--color-surface-raised)] p-2">
<div className="min-w-0 flex-1">
<div className="mb-0.5 text-[10px] font-medium text-[var(--color-text-muted)]">
Replying to{' '}
<span
className="font-semibold"
style={{
color: (() => {
const rc = colorMap.get(replyTo.author);
return rc ? getTeamColorSet(rc).text : 'var(--color-text-secondary)';
})(),
}}
>
@{replyTo.author}
</span>
<div className="mb-0.5 flex items-center gap-1 text-[10px] font-medium text-[var(--color-text-muted)]">
Replying to
<MemberBadge name={replyTo.author} color={colorMap.get(replyTo.author)} />
</div>
<div className="line-clamp-3 text-[11px] text-[var(--color-text-muted)]">
{replyTo.text}