diff --git a/src/renderer/components/team/members/MemberDraftRow.test.tsx b/src/renderer/components/team/members/MemberDraftRow.test.tsx index a3322f78..44f77a25 100644 --- a/src/renderer/components/team/members/MemberDraftRow.test.tsx +++ b/src/renderer/components/team/members/MemberDraftRow.test.tsx @@ -27,18 +27,32 @@ vi.mock('@renderer/components/team/RoleSelect', () => ({ vi.mock('@renderer/components/ui/button', () => ({ Button: ({ children, + className, onClick, disabled, + title, + 'aria-describedby': ariaDescribedBy, 'aria-label': ariaLabel, }: { children: React.ReactNode; + className?: string; onClick?: React.MouseEventHandler; disabled?: boolean; + title?: string; + 'aria-describedby'?: string; 'aria-label'?: string; }) => React.createElement( 'button', - { type: 'button', onClick, disabled, 'aria-label': ariaLabel }, + { + type: 'button', + className, + onClick, + disabled, + title, + 'aria-describedby': ariaDescribedBy, + 'aria-label': ariaLabel, + }, children ), })); @@ -204,6 +218,41 @@ describe('MemberDraftRow', () => { }); }); + it('shows model launch issues inline and keeps model controls expandable', () => { + const issueText = + 'Member alice uses Anthropic effort "medium", but Haiku 4.5 does not support it in the current runtime.'; + const { host, root } = renderMemberDraftRow({ + member: createMemberDraft({ + id: 'member-1', + name: 'alice', + roleSelection: 'developer', + providerId: 'anthropic', + model: 'claude-haiku-4-5-20251001', + effort: 'medium', + }), + modelIssueText: issueText, + }); + + const modelButton = host.querySelector( + 'button[aria-label="anthropic provider, claude-haiku-4-5-20251001"]' + )!; + + expect(host.textContent).toContain(issueText); + expect(modelButton.getAttribute('aria-describedby')).toContain('member-member-1-model-issue'); + expect(modelButton.parentElement?.getAttribute('title')).toBe(issueText); + + act(() => { + modelButton.click(); + }); + + expect(host.textContent).toContain('team-model-selector'); + expect(host.textContent).toContain('effort-selector'); + + act(() => { + root.unmount(); + }); + }); + it('warns custom Anthropic Sonnet teammates about plan/runtime billing when 200K limit is off', () => { const { host, root } = renderMemberDraftRow({ member: { diff --git a/src/renderer/components/team/members/MemberDraftRow.tsx b/src/renderer/components/team/members/MemberDraftRow.tsx index c62aaccf..07e8450f 100644 --- a/src/renderer/components/team/members/MemberDraftRow.tsx +++ b/src/renderer/components/team/members/MemberDraftRow.tsx @@ -247,6 +247,15 @@ export const MemberDraftRow = ({ const currentModelIssueText = modelIssueText ?? selectedModelUnavailableText ?? selectedModelIssueText ?? null; const hasModelIssue = Boolean(currentModelIssueText); + const modelButtonDisabled = (lockProviderModel && !canOpenLockedModelPanel) || isRemoved; + const modelButtonTitle = + [currentModelIssueText, modelTooltipText] + .filter((message): message is string => Boolean(message)) + .join('\n') || undefined; + const modelIssueDescriptionId = hasModelIssue ? `member-${member.id}-model-issue` : undefined; + const modelHelpDescriptionId = modelTooltipText ? `member-${member.id}-model-help` : undefined; + const modelButtonDescribedBy = + [modelIssueDescriptionId, modelHelpDescriptionId].filter(Boolean).join(' ') || undefined; const hasCustomProviderOrModel = !forceInheritedModelSettings && Boolean(member.providerId || member.model?.trim()); const showSonnetExtraUsageWarning = @@ -342,52 +351,46 @@ export const MemberDraftRow = ({ ) : null}
- - - - - - - {modelTooltipText || currentModelIssueText ? ( - - {currentModelIssueText ? ( -

{currentModelIssueText}

- ) : null} - {modelTooltipText ? ( -

- {modelTooltipText} -

- ) : null} -
- ) : null} -
+ + + + {modelTooltipText ? ( + + {modelTooltipText} + + ) : null} + {currentModelIssueText ? ( +

+ + {currentModelIssueText} +

+ ) : null}
{showWorktreeIsolationControls ? (