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:
parent
16bb2c0b63
commit
0e627c4b3f
3 changed files with 40 additions and 62 deletions
|
|
@ -957,17 +957,6 @@ export class TeamProvisioningService {
|
||||||
'Using ANTHROPIC_AUTH_TOKEN (proxy) mapped to ANTHROPIC_API_KEY for `-p` mode.'
|
'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);
|
const probe = await this.probeClaudeRuntime(claudePath, targetCwd, executionEnv);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,6 @@ function findProgressForTeam(
|
||||||
return matching[0] ?? null;
|
return matching[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const READY_DISMISS_MS = 5_000;
|
|
||||||
|
|
||||||
export const TeamProvisioningBanner = ({
|
export const TeamProvisioningBanner = ({
|
||||||
teamName,
|
teamName,
|
||||||
}: TeamProvisioningBannerProps): React.JSX.Element | null => {
|
}: TeamProvisioningBannerProps): React.JSX.Element | null => {
|
||||||
|
|
@ -49,28 +47,9 @@ export const TeamProvisioningBanner = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
// NOTE: we intentionally do NOT auto-dismiss "ready" banners.
|
||||||
if (progress?.state !== 'ready') {
|
// Users frequently need to inspect launch output after fast stop→start cycles,
|
||||||
return;
|
// and auto-dismiss can make it look like no progress/logs were produced.
|
||||||
}
|
|
||||||
// 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,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!progress || dismissed) {
|
if (!progress || dismissed) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import { useCallback, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer';
|
import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer';
|
||||||
import { ReplyQuoteBlock } from '@renderer/components/team/activity/ReplyQuoteBlock';
|
import { ReplyQuoteBlock } from '@renderer/components/team/activity/ReplyQuoteBlock';
|
||||||
|
import { MemberBadge } from '@renderer/components/team/MemberBadge';
|
||||||
import { MentionableTextarea } from '@renderer/components/ui/MentionableTextarea';
|
import { MentionableTextarea } from '@renderer/components/ui/MentionableTextarea';
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
|
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
|
||||||
import { getTeamColorSet } from '@renderer/constants/teamColors';
|
|
||||||
import { useDraftPersistence } from '@renderer/hooks/useDraftPersistence';
|
import { useDraftPersistence } from '@renderer/hooks/useDraftPersistence';
|
||||||
import { useMarkCommentsRead } from '@renderer/hooks/useMarkCommentsRead';
|
import { useMarkCommentsRead } from '@renderer/hooks/useMarkCommentsRead';
|
||||||
import { useStore } from '@renderer/store';
|
import { useStore } from '@renderer/store';
|
||||||
|
|
@ -14,7 +14,16 @@ import { getModifierKeyName } from '@renderer/utils/keyboardUtils';
|
||||||
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
||||||
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
|
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
|
||||||
import { formatDistanceToNow } from 'date-fns';
|
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 { MentionSuggestion } from '@renderer/types/mention';
|
||||||
import type { ResolvedTeamMember, TaskComment } from '@shared/types';
|
import type { ResolvedTeamMember, TaskComment } from '@shared/types';
|
||||||
|
|
@ -146,19 +155,30 @@ export const TaskCommentsSection = ({
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{visibleComments.map((comment) => (
|
{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)]">
|
<div className="mb-1 flex items-center gap-2 text-[10px] text-[var(--color-text-muted)]">
|
||||||
<span
|
<MemberBadge name={comment.author} color={colorMap.get(comment.author)} />
|
||||||
className="font-medium"
|
{comment.type === 'review_approved' ? (
|
||||||
style={{
|
<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">
|
||||||
color: (() => {
|
<CheckCircle2 size={10} />
|
||||||
const rc = colorMap.get(comment.author);
|
Approved
|
||||||
return rc ? getTeamColorSet(rc).text : 'var(--color-text-secondary)';
|
</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} />
|
||||||
{comment.author}
|
Review requested
|
||||||
</span>
|
</span>
|
||||||
|
) : null}
|
||||||
<span>
|
<span>
|
||||||
{(() => {
|
{(() => {
|
||||||
const date = new Date(comment.createdAt);
|
const date = new Date(comment.createdAt);
|
||||||
|
|
@ -290,19 +310,9 @@ export const TaskCommentsSection = ({
|
||||||
{replyTo ? (
|
{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="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="min-w-0 flex-1">
|
||||||
<div className="mb-0.5 text-[10px] font-medium text-[var(--color-text-muted)]">
|
<div className="mb-0.5 flex items-center gap-1 text-[10px] font-medium text-[var(--color-text-muted)]">
|
||||||
Replying to{' '}
|
Replying to
|
||||||
<span
|
<MemberBadge name={replyTo.author} color={colorMap.get(replyTo.author)} />
|
||||||
className="font-semibold"
|
|
||||||
style={{
|
|
||||||
color: (() => {
|
|
||||||
const rc = colorMap.get(replyTo.author);
|
|
||||||
return rc ? getTeamColorSet(rc).text : 'var(--color-text-secondary)';
|
|
||||||
})(),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
@{replyTo.author}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="line-clamp-3 text-[11px] text-[var(--color-text-muted)]">
|
<div className="line-clamp-3 text-[11px] text-[var(--color-text-muted)]">
|
||||||
{replyTo.text}
|
{replyTo.text}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue