Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/bumpy-sheep-sneeze.md
Original file line number Diff line number Diff line change
@@ -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.

---

Fix circular imports
5 changes: 5 additions & 0 deletions .changeset/violet-pets-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@viamrobotics/test-widgets': minor
---

Add `IsHoldingSomething` widget
2 changes: 1 addition & 1 deletion src/lib/client-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
WorldStateStoreClient,
} from '@viamrobotics/sdk'

import { getResourceAPI } from './resource.ts'
import { getResourceAPI } from './get-resource-api.ts'

export const clientMap = {
'rdk:component:arm': ArmClient,
Expand Down
3 changes: 2 additions & 1 deletion src/lib/components/widgets/do-command/do-command.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
import { PersistedState } from 'runed'

import { supportsDoCommand } from '$lib/client-map'
import { getResourceAPI, getResourceKey } from '$lib/resource'
import { getResourceAPI } from '$lib/get-resource-api'
import { getResourceKey } from '$lib/get-resource-key'

import ErrorDisplay from '../../error.svelte'
import { createDoCommandClient } from './create-do-command-client.svelte'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { render, screen } from '@testing-library/svelte'
Comment thread
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,
Comment thread
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,
})
})
})
5 changes: 5 additions & 0 deletions src/lib/components/widgets/gripper/gripper.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import StopButton from '$lib/components/stop-button.svelte'

import Grab from './grab.svelte'
import IsHoldingSomething from './is-holding-something.svelte'
import Open from './open.svelte'

interface Props {
Expand Down Expand Up @@ -63,6 +64,10 @@
{partID}
{resourceName}
/>
<IsHoldingSomething
{partID}
{resourceName}
/>
</div>
</div>
{/snippet}
Expand Down
57 changes: 57 additions & 0 deletions src/lib/components/widgets/gripper/is-holding-something.svelte
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>
4 changes: 4 additions & 0 deletions src/lib/get-resource-api.ts
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}`
5 changes: 5 additions & 0 deletions src/lib/get-resource-key.ts
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}`
3 changes: 2 additions & 1 deletion src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export {

export { clientForResource } from './client-map'
export * from './components'
export { getResourceAPI } from './get-resource-api'

export { providePip, usePip } from './pip/context.svelte'
export { getResourceAPI, hasWidget, showResourceWidget, widgetForResource } from './resource'
export { hasWidget, showResourceWidget, widgetForResource } from './resource'
6 changes: 1 addition & 5 deletions src/lib/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
SwitchWidget,
VisionServiceWidget,
} from './components'
import { getResourceAPI } from './get-resource-api.ts'

export type NamedResourceStatus = ResourceStatus & {
name: ResourceName
Expand Down Expand Up @@ -102,11 +103,6 @@ const resourceMap =
'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.

`${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
Expand Down
10 changes: 3 additions & 7 deletions src/routes/widgets/card-list-item.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,9 @@
import ResourceIcon from '$lib/components/resource-icon.svelte'
import SectionGroup from '$lib/components/section-group.svelte'
import DoCommandWidget from '$lib/components/widgets/do-command/do-command.svelte'
import {
getResourceAPI,
getResourceKey,
type NamedResourceStatus,
ResourceStatusText,
widgetForResource,
} from '$lib/resource'
import { getResourceAPI } from '$lib/get-resource-api'
import { getResourceKey } from '$lib/get-resource-key'
import { type NamedResourceStatus, ResourceStatusText, widgetForResource } from '$lib/resource'
import { scrollIntoView } from '$lib/scroll-into-view'

import ResourceStatus from './resource-status.svelte'
Expand Down
3 changes: 2 additions & 1 deletion src/routes/widgets/card-list.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import ErrorDisplay from '$lib/components/error.svelte'
import { getResourceKey, type NamedResourceStatus } from '$lib/resource'
import { getResourceKey } from '$lib/get-resource-key'
import { type NamedResourceStatus } from '$lib/resource'

import CardListItem from './card-list-item.svelte'
import NullState from './null-state.svelte'
Expand Down
3 changes: 2 additions & 1 deletion src/routes/widgets/resource-list.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import ErrorDisplay from '$lib/components/error.svelte'
import ResourceIcon from '$lib/components/resource-icon.svelte'
import { getResourceKey, type NamedResourceStatus } from '$lib/resource'
import { getResourceKey } from '$lib/get-resource-key'
import { type NamedResourceStatus } from '$lib/resource'

interface Props {
isLoading: boolean
Expand Down
Loading