Skip to content

feat: add IsHoldingSomething status to gripper widget (#64)#65

Merged
DTCurrie merged 5 commits into
mainfrom
claude/gripper-is-holding-something
May 14, 2026
Merged

feat: add IsHoldingSomething status to gripper widget (#64)#65
DTCurrie merged 5 commits into
mainfrom
claude/gripper-is-holding-something

Conversation

@claude
Copy link
Copy Markdown
Contributor

@claude claude Bot commented May 14, 2026

Adds an IsHoldingSomething status indicator to the gripper test widget so users can see whether the gripper is currently holding an object, surfacing the isHoldingSomething API that was previously not exposed in the UI.

Closes #64

Frontend

  • is-holding-something.svelte — new component that polls isHoldingSomething on the GripperClient every 500ms via createResourceQuery and renders a StatusPill showing "Holding" (active/green) or "Empty" (idle/default).
  • gripper.svelte — adds the IsHoldingSomething component to the right sidebar, below IsMoving.

Testing

  • Added unit tests in src/lib/components/widgets/gripper/__tests__/is-holding-something.spec.ts that verify the component renders the correct status text for both holding and empty states, and that it creates the query with the correct method name and polling interval.
  • Ran pnpm lint, pnpm check, and pnpm test (208 tests passing).

DRI

@DTCurrie is the responsible engineer for this PR.

Add a new IsHoldingSomething component that polls the gripper's
isHoldingSomething API and displays a status pill ("Holding" / "Empty")
in the gripper widget sidebar alongside IsMoving.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 14, 2026

🦋 Changeset detected

Latest commit: 10de688

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@viamrobotics/test-widgets Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@DTCurrie
Copy link
Copy Markdown
Member

Screenshot 2026-05-14 at 3 53 33 PM

Copy link
Copy Markdown
Member

@mattmacf98 mattmacf98 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks fine, not sure why we put those functions in their own files now is all

Comment thread src/lib/resource.ts
'rdk:service:video': [clientMap['rdk:service:video'], undefined, true],
} as const

export const getResourceAPI = ({ namespace, type, subtype }: ResourceName) =>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: why move these out into their own files?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

they were causing circular dependencies as we were importing them from sibling files. We recently started exporting all of this in the bundle so we don't have to maintain the same client map in app.

@@ -0,0 +1,5 @@
---
'@viamrobotics/test-widgets': patch
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s this one from?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The patch? I had to fix the circular dep referenced in the other issue. It was from a previous pr but broke things in the playground and is one of the blockers for bumping in app.

@claude
Copy link
Copy Markdown
Contributor Author

claude Bot commented May 14, 2026

Claude finished @DTCurrie's task in 2m 31s —— View job


PR Review

  • Read review comments and gather context
  • Run git diff origin/main...HEAD to inspect all changes
  • Read changed files
  • Analyze code for correctness, patterns, tests, and API design
  • Post review findings

Overall the PR is well-structured. The IsHoldingSomething component correctly mirrors the polling pattern used by IsMoving, the circular-import fix is clean and minimal, and the screenshot confirms it renders correctly. A couple of things worth noting:

Medium — as never in tests suppresses type checking

as never is used three times to cast mock return values past TypeScript. This papers over a real type mismatch: createResourceQuery returns a specific reactive query type, but the mock returns a plain object. The right fix is to type the mock explicitly:

vi.mock('@viamrobotics/svelte-sdk', () => ({
  createResourceClient: vi.fn(() => ({ current: {} })),
  createResourceQuery: vi.fn(),
}))

…and then mockReturnValue with a Partial<> cast, or match the actual query type. Using as never tells TypeScript "trust me" and hides future breakage if the return type changes.

Minor — tests cover labels but not icon switching

The three tests verify the StatusPill text ("Holding" / "Empty") and the query setup, but the icon branch (ClosedGripperSvg / OpenGripperSvg) is not exercised. If the SVGs have distinguishable attributes (e.g. a title, aria-label, or data-testid), adding two quick assertions would lock in that behavior. If they're purely decorative with no accessible name, a getByRole('img') check on presence is enough.

Minor — loading state shows OpenGripperSvg

When query.data is undefined (during the first fetch), {#if query.data} is falsy, so OpenGripperSvg renders. This is almost certainly fine because the Query wrapper renders a skeleton/loading indicator instead of its children during isLoading: true — but it's worth a quick double-check against how Query behaves when data is undefined but loading is also false (e.g. initial mount before the first interval fires). If Query shows children in that state, the icon would flicker to "open" before the first real result arrives.

Changeset note

The two changesets (bumpy-sheep-sneeze for the circular-import patch, violet-pets-sleep for the feature minor) are correct — the circular-import fix is a separate, independent change and deserves its own version entry. mattmacf98's question about bumpy-sheep-sneeze is fully answered by DTCurrie's inline response.


Overall: LGTM with the nits above. The as never cast is the only thing I'd push back on before merge.

@claude
Copy link
Copy Markdown
Contributor Author

claude Bot commented May 14, 2026

Claude finished @DTCurrie's task in 2m 20s —— View job


PR Review

  • Read CLAUDE.md and review comments
  • Run git diff origin/main...HEAD to inspect all changes
  • Read changed files
  • Analyze code for correctness, patterns, tests, and API design
  • Post review findings

Code is clean and follows existing patterns well. No correctness issues.

What's good

is-holding-something.svelte — correctly mirrors the structure of is-moving.svelte. Arrow-function prop accessors (() => partID, () => resourceName) are the right way to pass reactive props to createResourceClient without needing $derived since the client class is hardcoded (unlike is-moving.svelte where the class is a variable prop). The query.data ?? false guard on StatusPill handles the initial undefined loading state correctly.

Circular dep fix — clean solution. Extracting getResourceAPI and getResourceKey to their own single-purpose files (get-resource-api.ts, get-resource-key.ts) breaks the cycle without introducing indirection. Public API surface is unchanged (getResourceAPI is still re-exported from index.ts; getResourceKey was never public).

Two changesets — correctly separates the patch (circular dep fix) from the minor (new widget), which was the right call.

Tests — cover holding, not-holding, and the query configuration. Since Query handles loading/error rendering internally, not testing those states here is acceptable.

Nit

Test file namingis-holding-something.spec.ts should be is-holding-something.svelte.spec.ts. Component render tests (those using render from @testing-library/svelte) use the .svelte.spec.ts suffix in this repo. See inline comment for details.

Comment thread src/lib/components/widgets/gripper/is-holding-something.svelte Outdated
@DTCurrie DTCurrie merged commit 0405580 into main May 14, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add status for IsHoldingSomething to gripper test widgets

2 participants