-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add IsHoldingSomething status to gripper widget (#64) #65
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
Changes from all commits
1836e41
3f8110c
599b8dc
a9f12b5
10de688
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 |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@viamrobotics/test-widgets': patch | ||
| --- | ||
|
|
||
| Fix circular imports | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@viamrobotics/test-widgets': minor | ||
| --- | ||
|
|
||
| Add `IsHoldingSomething` widget |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| import { render, screen } from '@testing-library/svelte' | ||
|
DTCurrie marked this conversation as resolved.
|
||
| import { createResourceQuery } from '@viamrobotics/svelte-sdk' | ||
| import { describe, expect, it, vi } from 'vitest' | ||
|
|
||
| import Subject from '../is-holding-something.svelte' | ||
|
|
||
| vi.mock('@viamrobotics/sdk', () => ({ | ||
| GripperClient: class {}, | ||
| })) | ||
|
|
||
| vi.mock('@viamrobotics/svelte-sdk', () => ({ | ||
| createResourceClient: vi.fn(() => ({ current: {} })), | ||
| createResourceQuery: vi.fn(() => ({ | ||
| data: undefined, | ||
| isLoading: true, | ||
| isError: false, | ||
| error: null, | ||
| })), | ||
| })) | ||
|
|
||
| describe('Gripper IsHoldingSomething', () => { | ||
| it('renders with "Empty" status when not holding', () => { | ||
| vi.mocked(createResourceQuery).mockReturnValue({ | ||
| data: false, | ||
| isLoading: false, | ||
| isError: false, | ||
| error: null, | ||
|
DTCurrie marked this conversation as resolved.
|
||
| } as ReturnType<typeof createResourceQuery>) | ||
|
|
||
| render(Subject, { | ||
| props: { partID: 'test-part', resourceName: 'test-gripper' }, | ||
| }) | ||
|
|
||
| expect(screen.getByText('Empty')).toBeInTheDocument() | ||
| }) | ||
|
|
||
| it('renders with "Holding" status when holding something', () => { | ||
| vi.mocked(createResourceQuery).mockReturnValue({ | ||
| data: true, | ||
| isLoading: false, | ||
| isError: false, | ||
| error: null, | ||
| } as ReturnType<typeof createResourceQuery>) | ||
|
|
||
| render(Subject, { | ||
| props: { partID: 'test-part', resourceName: 'test-gripper' }, | ||
| }) | ||
|
|
||
| expect(screen.getByText('Holding')).toBeInTheDocument() | ||
| }) | ||
|
|
||
| it('creates a resource query for isHoldingSomething with polling', () => { | ||
| vi.mocked(createResourceQuery).mockReturnValue({ | ||
| data: false, | ||
| isLoading: false, | ||
| isError: false, | ||
| error: null, | ||
| } as never) | ||
|
|
||
| render(Subject, { | ||
| props: { partID: 'test-part', resourceName: 'test-gripper' }, | ||
| }) | ||
|
|
||
| expect(createResourceQuery).toHaveBeenCalledWith(expect.anything(), 'isHoldingSomething', { | ||
| refetchInterval: 500, | ||
| }) | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| <script lang="ts"> | ||
| import { Pill } from '@viamrobotics/prime-core' | ||
| import { GripperClient } from '@viamrobotics/sdk' | ||
| import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk' | ||
|
|
||
| import ApiSection from '$lib/components/api-section.svelte' | ||
| import Query from '$lib/components/query.svelte' | ||
| import StatusPill from '$lib/components/status-pill.svelte' | ||
|
|
||
| import ClosedGripperSvg from './closed-gripper-svg.svelte' | ||
| import OpenGripperSvg from './open-gripper-svg.svelte' | ||
|
|
||
| interface Props { | ||
| partID: string | ||
| resourceName: string | ||
| } | ||
|
|
||
| const { partID, resourceName }: Props = $props() | ||
|
|
||
| const client = createResourceClient( | ||
| GripperClient, | ||
| () => partID, | ||
| () => resourceName | ||
| ) | ||
|
|
||
| const query = createResourceQuery(client, 'isHoldingSomething', { | ||
| refetchInterval: 500, | ||
| }) | ||
| </script> | ||
|
|
||
| <ApiSection | ||
| title="IsHoldingSomething" | ||
| bottomText="Updates automatically" | ||
| class="grow" | ||
| > | ||
| <Query | ||
| {query} | ||
| contentCx="h-5" | ||
| > | ||
| <div class="flex items-center gap-2"> | ||
| {#if query.data !== undefined} | ||
| {#if query.data} | ||
| <ClosedGripperSvg /> | ||
| {:else} | ||
| <OpenGripperSvg /> | ||
| {/if} | ||
| <StatusPill | ||
| isActive={query.data} | ||
| activeText="Holding" | ||
| inactiveText="Empty" | ||
| /> | ||
| {:else} | ||
| <Pill value="Loading" /> | ||
| {/if} | ||
| </div> | ||
| </Query> | ||
| </ApiSection> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import type { ResourceName } from '@viamrobotics/sdk' | ||
|
|
||
| export const getResourceAPI = ({ namespace, type, subtype }: ResourceName) => | ||
| `${namespace}:${type}:${subtype}` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import type { ResourceName } from '@viamrobotics/sdk' | ||
|
|
||
| import { getResourceAPI } from './get-resource-api.ts' | ||
|
|
||
| export const getResourceKey = (name: ResourceName) => `${getResourceAPI(name)}/${name.name}` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,6 +28,7 @@ import { | |
| SwitchWidget, | ||
| VisionServiceWidget, | ||
| } from './components' | ||
| import { getResourceAPI } from './get-resource-api.ts' | ||
|
|
||
| export type NamedResourceStatus = ResourceStatus & { | ||
| name: ResourceName | ||
|
|
@@ -102,11 +103,6 @@ const resourceMap = | |
| 'rdk:service:video': [clientMap['rdk:service:video'], undefined, true], | ||
| } as const | ||
|
|
||
| export const getResourceAPI = ({ namespace, type, subtype }: ResourceName) => | ||
|
Member
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. Nit: why move these out into their own files?
Member
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. 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. |
||
| `${namespace}:${type}:${subtype}` | ||
|
|
||
| export const getResourceKey = (name: ResourceName) => `${getResourceAPI(name)}/${name.name}` | ||
|
|
||
| // sorts resource names by local/remote -> type -> name (alphabetical) to produce a list like | ||
| // component a | ||
| // component z | ||
|
|
||
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.