-
Notifications
You must be signed in to change notification settings - Fork 3.3k
fix(signals): make inbox example cards and tool-off badge answer clicks #89589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
47e77f2
4724afb
437744a
8dbb8ad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -495,11 +495,30 @@ const AgentRow = memo(function AgentRow({ | |
| </div> | ||
| <span className="truncate text-xs leading-4 text-muted">{agent.watches}</span> | ||
| </div> | ||
| {tag && ( | ||
| {toolOff && tool?.enablement ? ( | ||
| // A live badge, not a dead one: clicking it turns the tool on, the same action the | ||
| // expansion offers one disclosure level below. | ||
| <Tooltip title={`${tool.toolName} is off, so this source has nothing to read. Turn it on.`}> | ||
| <LemonTag | ||
| type="warning" | ||
| size="small" | ||
| forceClickable | ||
| icon={enablingTool ? <Spinner /> : undefined} | ||
| onClick={(e) => { | ||
| e.stopPropagation() | ||
| if (!enablingTool) { | ||
| onEnableTool(tool) | ||
| } | ||
| }} | ||
| > | ||
| Turn it on | ||
| </LemonTag> | ||
| </Tooltip> | ||
|
Comment on lines
+503
to
+516
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The new tool action cannot be used with a keyboardWhy we think it's a valid issue
Issue description
Suggested fixUse a Prompt to fix with AI (copy-paste)
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a real gap and worth fixing — I've left it for a human to choose the approach rather than pick one unattended. Confirmed: the badge renders with a button role (via The reason it needs a human call is that the three sensible fixes each carry a trade-off:
My recommendation: go with the |
||
| ) : tag ? ( | ||
| <LemonTag type={tag.type} size="small"> | ||
| {tag.label} | ||
| </LemonTag> | ||
| )} | ||
| ) : null} | ||
| <span className="w-38 shrink-0 truncate text-right text-xs text-muted"> | ||
| {entities.length > 0 && `${enabledCount} of ${entities.length} ${agent.entityNoun} on`} | ||
| </span> | ||
|
|
@@ -585,7 +604,7 @@ export function AgentsRoster(): JSX.Element { | |
| isHealthChecksToggling, | ||
| isCiSignalsToggling, | ||
| toolStatusBySource, | ||
| enablingTool, | ||
| enablingTools, | ||
| } = useValues(signalSourcesLogic) | ||
| const { | ||
| toggleConversations, | ||
|
|
@@ -832,16 +851,15 @@ export function AgentsRoster(): JSX.Element { | |
| agent.steerable && state.sourceConfig && !state.sourceConfig.id.startsWith('new_') | ||
| ? state.sourceConfig | ||
| : null | ||
| const enablement = toolStatusBySource[agent.source]?.enablement | ||
| return ( | ||
| <AgentRow | ||
| key={agent.source} | ||
| agent={agent} | ||
| state={state} | ||
| tool={toolStatusBySource[agent.source]} | ||
| expanded={expandedSource === agent.source} | ||
| enablingTool={ | ||
| !!enablingTool && enablingTool === toolStatusBySource[agent.source]?.enablement | ||
| } | ||
| enablingTool={!!enablement && enablingTools.has(enablement)} | ||
| onExpand={() => | ||
| setExpandedSource((current) => (current === agent.source ? null : agent.source)) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| import '@testing-library/jest-dom' | ||
|
|
||
| import { cleanup, fireEvent, render } from '@testing-library/react' | ||
|
|
||
| import { InboxOnboardingTakeover } from './InboxOnboarding' | ||
|
|
||
| // The manual-setup escape hatch pulls in `inboxOnboardingLogic` (kea); it is unrelated to the card click. | ||
| jest.mock('./ManualSetupAction', () => ({ ManualSetupAction: () => null })) | ||
| jest.mock('../../inboxAnalytics', () => ({ | ||
| captureInboxWelcomeViewed: jest.fn(), | ||
| captureInboxWelcomeCommandCopied: jest.fn(), | ||
| })) | ||
| jest.mock('./meep', () => ({ playMeep: jest.fn() })) | ||
| jest.mock('lib/components/TZLabel', () => ({ TZLabel: ({ time }: { time: string }) => <span>{time}</span> })) | ||
|
|
||
| describe('InboxOnboardingTakeover example cards', () => { | ||
| beforeAll(() => { | ||
| // jsdom does not implement scrollIntoView; stub it so the click handler can call it. | ||
| Element.prototype.scrollIntoView = jest.fn() | ||
| }) | ||
| afterEach(cleanup) | ||
|
|
||
| it('answers a click on an example card by scrolling to the setup command and pulsing it', () => { | ||
| const { container, getAllByLabelText } = render(<InboxOnboardingTakeover />) | ||
| // A dead click leaves the DOM unchanged; the pulse ring must be absent before the click. | ||
| expect(container.querySelector('.InboxOnboarding__commandPulse')).toBeNull() | ||
|
|
||
| const overlays = getAllByLabelText(/Jump to the setup command/i) | ||
| expect(overlays.length).toBeGreaterThan(0) | ||
| fireEvent.click(overlays[0]) | ||
|
|
||
| expect(Element.prototype.scrollIntoView).toHaveBeenCalled() | ||
| expect(container.querySelector('.InboxOnboarding__commandPulse')).not.toBeNull() | ||
| }) | ||
| }) |
Uh oh!
There was an error while loading. Please reload this page.