@viamrobotics/test-widgets 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/README.md +1 -1
  2. package/dist/api-docs-href.d.ts +8 -0
  3. package/dist/api-docs-href.js +17 -0
  4. package/dist/client-map.d.ts +30 -30
  5. package/dist/client-map.js +32 -29
  6. package/dist/components/angle-unit-toggle.svelte +1 -4
  7. package/dist/components/api-section.svelte +21 -23
  8. package/dist/components/api-section.svelte.d.ts +2 -0
  9. package/dist/components/index.d.ts +21 -0
  10. package/dist/components/index.js +21 -0
  11. package/dist/components/is-moving.svelte +4 -5
  12. package/dist/components/is-moving.svelte.d.ts +1 -0
  13. package/dist/components/mutation-section.svelte +20 -23
  14. package/dist/components/mutation-section.svelte.d.ts +2 -0
  15. package/dist/components/section-title.svelte +63 -0
  16. package/dist/components/section-title.svelte.d.ts +14 -0
  17. package/dist/components/widgets/arm/arm.svelte +25 -29
  18. package/dist/components/widgets/arm/get-joint-positions-widget.svelte +36 -0
  19. package/dist/components/widgets/arm/get-joint-positions-widget.svelte.d.ts +7 -0
  20. package/dist/components/widgets/arm/is-moving-widget.svelte +20 -0
  21. package/dist/components/widgets/arm/is-moving-widget.svelte.d.ts +7 -0
  22. package/dist/components/widgets/arm/joint-position-editor.svelte +89 -0
  23. package/dist/components/widgets/arm/joint-position-editor.svelte.d.ts +11 -0
  24. package/dist/components/widgets/arm/joint-position-quick-move.svelte +85 -0
  25. package/dist/components/widgets/arm/joint-position-quick-move.svelte.d.ts +9 -0
  26. package/dist/components/widgets/arm/joint-position-slider.svelte +36 -0
  27. package/dist/components/widgets/arm/joint-position-slider.svelte.d.ts +9 -0
  28. package/dist/components/widgets/arm/move-to-joint-positions-widget.svelte +9 -5
  29. package/dist/components/widgets/arm/move-to-joint-positions.svelte +73 -127
  30. package/dist/components/widgets/arm/move-to-joint-positions.svelte.d.ts +1 -0
  31. package/dist/components/widgets/arm/move-to-position.svelte +31 -3
  32. package/dist/components/widgets/audio-input/audio-input.svelte +2 -0
  33. package/dist/components/widgets/audio-input/get-properties-widget.svelte +43 -0
  34. package/dist/components/widgets/audio-input/get-properties-widget.svelte.d.ts +7 -0
  35. package/dist/components/widgets/audio-output/audio-output.svelte +2 -0
  36. package/dist/components/widgets/audio-output/get-properties-widget.svelte +43 -0
  37. package/dist/components/widgets/audio-output/get-properties-widget.svelte.d.ts +7 -0
  38. package/dist/components/widgets/base/base.svelte +9 -1
  39. package/dist/components/widgets/base/is-moving-widget.svelte +20 -0
  40. package/dist/components/widgets/base/is-moving-widget.svelte.d.ts +7 -0
  41. package/dist/components/widgets/base/quick-move.svelte +12 -5
  42. package/dist/components/widgets/camera/camera.svelte +156 -142
  43. package/dist/components/widgets/camera/live-or-polling-video.svelte +9 -1
  44. package/dist/components/widgets/discovery/discovery.svelte +1 -0
  45. package/dist/components/widgets/encoder/encoder-position-type.d.ts +8 -0
  46. package/dist/components/widgets/encoder/encoder-position-type.js +20 -0
  47. package/dist/components/widgets/encoder/encoder.svelte +5 -20
  48. package/dist/components/widgets/encoder/get-position-widget.svelte +54 -0
  49. package/dist/components/widgets/encoder/get-position-widget.svelte.d.ts +7 -0
  50. package/dist/components/widgets/gantry/gantry.svelte +28 -5
  51. package/dist/components/widgets/gantry/get-position-widget.svelte +43 -0
  52. package/dist/components/widgets/gantry/get-position-widget.svelte.d.ts +7 -0
  53. package/dist/components/widgets/gantry/is-moving-widget.svelte +20 -0
  54. package/dist/components/widgets/gantry/is-moving-widget.svelte.d.ts +7 -0
  55. package/dist/components/widgets/generic/generic.svelte +8 -1
  56. package/dist/components/widgets/gripper/gripper.svelte +11 -5
  57. package/dist/components/widgets/gripper/is-holding-something.svelte +2 -4
  58. package/dist/components/widgets/gripper/is-moving-widget.svelte +20 -0
  59. package/dist/components/widgets/gripper/is-moving-widget.svelte.d.ts +7 -0
  60. package/dist/components/widgets/input-controller/input-controller.svelte +2 -1
  61. package/dist/components/widgets/motor/is-moving-widget.svelte +20 -0
  62. package/dist/components/widgets/motor/is-moving-widget.svelte.d.ts +7 -0
  63. package/dist/components/widgets/motor/motor.svelte +13 -9
  64. package/dist/components/widgets/movement-sensor/get-accuracy-widget.svelte +38 -0
  65. package/dist/components/widgets/movement-sensor/get-accuracy-widget.svelte.d.ts +7 -0
  66. package/dist/components/widgets/movement-sensor/get-compass-heading-widget.svelte +38 -0
  67. package/dist/components/widgets/movement-sensor/get-compass-heading-widget.svelte.d.ts +7 -0
  68. package/dist/components/widgets/movement-sensor/get-orientation-widget.svelte +38 -0
  69. package/dist/components/widgets/movement-sensor/get-orientation-widget.svelte.d.ts +7 -0
  70. package/dist/components/widgets/movement-sensor/get-position-widget.svelte +38 -0
  71. package/dist/components/widgets/movement-sensor/get-position-widget.svelte.d.ts +7 -0
  72. package/dist/components/widgets/movement-sensor/movement-sensor.svelte +53 -26
  73. package/dist/components/widgets/power-sensor/get-current-widget.svelte +38 -0
  74. package/dist/components/widgets/power-sensor/get-current-widget.svelte.d.ts +7 -0
  75. package/dist/components/widgets/power-sensor/get-power-widget.svelte +38 -0
  76. package/dist/components/widgets/power-sensor/get-power-widget.svelte.d.ts +7 -0
  77. package/dist/components/widgets/power-sensor/get-voltage-widget.svelte +38 -0
  78. package/dist/components/widgets/power-sensor/get-voltage-widget.svelte.d.ts +7 -0
  79. package/dist/components/widgets/power-sensor/power-sensor.svelte +4 -0
  80. package/dist/components/widgets/sensor/sensor.svelte +1 -0
  81. package/dist/components/widgets/servo/is-moving-widget.svelte +20 -0
  82. package/dist/components/widgets/servo/is-moving-widget.svelte.d.ts +7 -0
  83. package/dist/components/widgets/servo/servo.svelte +10 -2
  84. package/dist/components/widgets/slam/get-position-widget.svelte +38 -0
  85. package/dist/components/widgets/slam/get-position-widget.svelte.d.ts +7 -0
  86. package/dist/components/widgets/slam/move-on-map.svelte +4 -1
  87. package/dist/components/widgets/slam/slam.svelte +4 -1
  88. package/dist/components/widgets/vision-service/context.svelte.d.ts +1 -0
  89. package/dist/components/widgets/vision-service/context.svelte.js +7 -0
  90. package/dist/components/widgets/vision-service/detection-row.svelte +38 -0
  91. package/dist/components/widgets/vision-service/detection-row.svelte.d.ts +8 -0
  92. package/dist/components/widgets/vision-service/detection.svelte +7 -4
  93. package/dist/components/widgets/vision-service/legend.svelte +14 -11
  94. package/dist/components/widgets/vision-service/vision-service.svelte +9 -10
  95. package/dist/index.d.ts +5 -1
  96. package/dist/index.js +6 -1
  97. package/dist/pip/context.svelte.d.ts +2 -0
  98. package/dist/pip/context.svelte.js +48 -20
  99. package/dist/resource-triplet.d.ts +37 -0
  100. package/dist/resource-triplet.js +37 -0
  101. package/dist/resource-widget.js +187 -0
  102. package/dist/resource.d.ts +0 -9
  103. package/dist/resource.js +0 -72
  104. package/package.json +7 -4
@@ -12,6 +12,7 @@
12
12
  createRefetchIntervalStore,
13
13
  RefetchIntervals,
14
14
  } from '../../refetch-interval-store.svelte'
15
+ import SectionTitle from '../../section-title.svelte'
15
16
 
16
17
  import PCDWidget from '../pcd/pcd-widget.svelte'
17
18
  import ExportScreenshot from './export-screenshot.svelte'
@@ -150,166 +151,179 @@
150
151
  }
151
152
 
152
153
  const headingID = $props.id()
154
+ const getImagesHeadingID = `${headingID}-images`
155
+ const getPointCloudHeadingID = `${headingID}-point-cloud`
153
156
  </script>
154
157
 
155
158
  <ConnectionStatus {partID}>
156
159
  {#snippet connected()}
157
- {#if isPlaying}
158
- <div class="flex gap-4 p-4 pb-3">
159
- <RefetchController
160
- {refetchInterval}
161
- allowLive
162
- queries={[imageQuery, pointcloudQuery]}
160
+ <section
161
+ class="flex flex-col"
162
+ aria-labelledby={getImagesHeadingID}
163
+ >
164
+ <div class="flex flex-col gap-0.5 p-4 pb-0">
165
+ <SectionTitle
166
+ title="GetImages"
167
+ api="rdk:component:camera"
168
+ headingId={getImagesHeadingID}
163
169
  />
164
- {#if sourceNames.length > 0 && refetchInterval.current !== RefetchIntervals.LIVE}
165
- <Label position="left">
166
- Source
167
- <Select
168
- value={selectedSource}
169
- on:change={onSourceSelect}
170
- slot="input"
171
- >
172
- {#each sourceNames as name (name)}
173
- <option value={name}>{name}</option>
174
- {/each}
175
- </Select>
176
- </Label>
177
- {/if}
178
- {#if panoCoverage}
179
- <Label>
180
- {panoToggleLabel}
181
- <ToggleButtons
182
- slot="input"
183
- options={['On', 'Off']}
184
- selected={displayAs360 ? 'On' : 'Off'}
185
- on:input={(event) => {
186
- displayAs360 = event.detail === 'On'
187
- }}
188
- />
189
- </Label>
190
- {/if}
191
170
  </div>
192
- {/if}
193
- <div class="flex h-full w-full gap-4 p-4">
194
- <div class="grow">
195
- {#if isPlaying}
196
- {#if displayAs360}
197
- {#if isLive}
198
- <!-- renderMode="always" keeps the live VideoTexture advancing each frame -->
199
- <Canvas renderMode="always">
200
- <LiveThreeSixtyCameraView
201
- {partID}
202
- {resourceName}
203
- coverage={panoCoverage}
204
- />
205
- </Canvas>
171
+ {#if isPlaying}
172
+ <div class="flex gap-4 p-4 pb-3">
173
+ <RefetchController
174
+ {refetchInterval}
175
+ allowLive
176
+ queries={[imageQuery, pointcloudQuery]}
177
+ />
178
+ {#if sourceNames.length > 0 && refetchInterval.current !== RefetchIntervals.LIVE}
179
+ <Label position="left">
180
+ Source
181
+ <Select
182
+ value={selectedSource}
183
+ on:change={onSourceSelect}
184
+ slot="input"
185
+ >
186
+ {#each sourceNames as name (name)}
187
+ <option value={name}>{name}</option>
188
+ {/each}
189
+ </Select>
190
+ </Label>
191
+ {/if}
192
+ {#if panoCoverage}
193
+ <Label>
194
+ {panoToggleLabel}
195
+ <ToggleButtons
196
+ slot="input"
197
+ options={['On', 'Off']}
198
+ selected={displayAs360 ? 'On' : 'Off'}
199
+ on:input={(event) => {
200
+ displayAs360 = event.detail === 'On'
201
+ }}
202
+ />
203
+ </Label>
204
+ {/if}
205
+ </div>
206
+ {/if}
207
+ <div class="flex h-full w-full gap-4 p-4">
208
+ <div class="grow">
209
+ {#if isPlaying}
210
+ {#if displayAs360}
211
+ {#if isLive}
212
+ <!-- renderMode="always" keeps the live VideoTexture advancing each frame -->
213
+ <Canvas renderMode="always">
214
+ <LiveThreeSixtyCameraView
215
+ {partID}
216
+ {resourceName}
217
+ coverage={panoCoverage}
218
+ />
219
+ </Canvas>
220
+ {:else}
221
+ <Canvas>
222
+ <ThreeSixtyCameraView
223
+ data={imageQuery.data}
224
+ coverage={panoCoverage}
225
+ />
226
+ </Canvas>
227
+ {/if}
206
228
  {:else}
207
- <Canvas>
208
- <ThreeSixtyCameraView
209
- data={imageQuery.data}
210
- coverage={panoCoverage}
211
- />
212
- </Canvas>
229
+ <LiveOrPollingVideo
230
+ {partID}
231
+ {resourceName}
232
+ showResolutionOptions
233
+ {isLive}
234
+ data={imageQuery.data}
235
+ error={imageQuery.error}
236
+ isLoading={imageQuery.isLoading}
237
+ refetch={imageQuery.refetch}
238
+ showMousePositionTooltip={mousePostionTooltip === 'On'}
239
+ sourceName={selectedSource}
240
+ />
213
241
  {/if}
214
242
  {:else}
215
- <LiveOrPollingVideo
216
- {partID}
217
- {resourceName}
218
- showResolutionOptions
219
- {isLive}
220
- data={imageQuery.data}
221
- error={imageQuery.error}
222
- isLoading={imageQuery.isLoading}
223
- refetch={imageQuery.refetch}
224
- showMousePositionTooltip={mousePostionTooltip === 'On'}
243
+ <div class="bg-medium flex h-64 w-80 items-center justify-center">
244
+ <Button
245
+ icon="play-circle-outline"
246
+ variant="dark"
247
+ onclick={() => {
248
+ isPlaying = true
249
+ }}
250
+ >
251
+ Start feed
252
+ </Button>
253
+ </div>
254
+ {/if}
255
+ </div>
256
+ {#if isPlaying}
257
+ <div class="flex flex-col items-start gap-2">
258
+ <ExportScreenshot
259
+ name={client.current?.name ?? ''}
225
260
  sourceName={selectedSource}
261
+ getImage={exportScreenshotQuery.refetch}
226
262
  />
227
- {/if}
228
- {:else}
229
- <div class="bg-medium flex h-64 w-80 items-center justify-center">
230
- <Button
231
- icon="play-circle-outline"
232
- variant="dark"
233
- onclick={() => {
234
- isPlaying = true
235
- }}
236
- >
237
- Start feed
238
- </Button>
239
- </div>
240
- {/if}
241
- </div>
242
- {#if isPlaying}
243
- <div class="flex flex-col items-start gap-2">
244
- <ExportScreenshot
245
- name={client.current?.name ?? ''}
246
- sourceName={selectedSource}
247
- getImage={exportScreenshotQuery.refetch}
248
- />
249
- {#if addImageToDataset}
250
- <Button
251
- icon="layers-triple-outline"
252
- onclick={async () => {
253
- let imgData
254
- if (refetchInterval.current === RefetchIntervals.LIVE) {
255
- const { isSuccess, data } = await imageQuery.refetch()
256
- if (!isSuccess) return
257
- imgData = data
258
- } else {
259
- imgData = imageQuery.data
260
- }
263
+ {#if addImageToDataset}
264
+ <Button
265
+ icon="layers-triple-outline"
266
+ onclick={async () => {
267
+ let imgData
268
+ if (refetchInterval.current === RefetchIntervals.LIVE) {
269
+ const { isSuccess, data } = await imageQuery.refetch()
270
+ if (!isSuccess) return
271
+ imgData = data
272
+ } else {
273
+ imgData = imageQuery.data
274
+ }
261
275
 
262
- const matchingImage = pickImageForSource(imgData?.images, selectedSource)
263
- const image = matchingImage?.image
264
- const mimeType = matchingImage?.mimeType
276
+ const matchingImage = pickImageForSource(imgData?.images, selectedSource)
277
+ const image = matchingImage?.image
278
+ const mimeType = matchingImage?.mimeType
265
279
 
266
- if (image) {
267
- addImageToDataset({
268
- binaryData: new Uint8Array(image),
269
- partID,
270
- componentType: 'camera',
271
- componentName: resourceName,
272
- methodName: 'captureAllFromCamera',
273
- mimeType: mimeType ?? 'image/png',
274
- dataRequestTimes: [new Date(), new Date()],
275
- })
276
- }
277
- }}
278
- >
279
- Add current image to dataset
280
- </Button>
281
- {/if}
282
- {#if !isFirefox}
283
- <PictureInPictureButton
284
- {resourceName}
285
- rate={refetchInterval.current}
286
- />
287
- {/if}
288
- <Label>
289
- Mouse Position Tooltip
280
+ if (image) {
281
+ addImageToDataset({
282
+ binaryData: new Uint8Array(image),
283
+ partID,
284
+ componentType: 'camera',
285
+ componentName: resourceName,
286
+ methodName: 'captureAllFromCamera',
287
+ mimeType: mimeType ?? 'image/png',
288
+ dataRequestTimes: [new Date(), new Date()],
289
+ })
290
+ }
291
+ }}
292
+ >
293
+ Add current image to dataset
294
+ </Button>
295
+ {/if}
296
+ {#if !isFirefox}
297
+ <PictureInPictureButton
298
+ {resourceName}
299
+ rate={refetchInterval.current}
300
+ />
301
+ {/if}
302
+ <Label>
303
+ Mouse Position Tooltip
290
304
 
291
- <ToggleButtons
292
- slot="input"
293
- options={['On', 'Off']}
294
- selected={mousePostionTooltip}
295
- on:input={setMousePostionTooltip}
296
- />
297
- </Label>
298
- </div>
299
- {/if}
300
- </div>
305
+ <ToggleButtons
306
+ slot="input"
307
+ options={['On', 'Off']}
308
+ selected={mousePostionTooltip}
309
+ on:input={setMousePostionTooltip}
310
+ />
311
+ </Label>
312
+ </div>
313
+ {/if}
314
+ </div>
315
+ </section>
301
316
 
302
317
  <section
303
318
  class="flex flex-col gap-4 p-4"
304
- aria-labelledby={headingID}
319
+ aria-labelledby={getPointCloudHeadingID}
305
320
  >
306
- <div>
307
- <h3
308
- id={headingID}
309
- class="pb-1.5 font-semibold"
310
- >
311
- GetPointCloud
312
- </h3>
321
+ <div class="flex flex-col gap-0.5">
322
+ <SectionTitle
323
+ title="GetPointCloud"
324
+ api="rdk:component:camera"
325
+ headingId={getPointCloudHeadingID}
326
+ />
313
327
  <p class="text-subtle-2 text-xs">
314
328
  Get depth measurement data from cameras with depth sensing support
315
329
  </p>
@@ -14,6 +14,7 @@
14
14
  import Progress from '../../progress.svelte'
15
15
  import { formatNumeric } from '../../../format'
16
16
  import { useMeasureFps } from '../../../fps.svelte'
17
+ import { usePip } from '../../../pip/context.svelte'
17
18
 
18
19
  import { getBlobForViamDepth, VIAM_DEPTH_MIME_TYPE } from './decode-viam-depth'
19
20
  import { pickImageForSource } from './pick-image-for-source'
@@ -52,7 +53,13 @@
52
53
  let vfcID = 0
53
54
  let liveStreamStart: DOMHighResTimeStamp | undefined
54
55
 
56
+ const pip = usePip()
57
+
55
58
  const setMediaStream = (mediaStream: MediaStream | null) => {
59
+ if (mediaStream) {
60
+ pip.setStream(resourceName, mediaStream)
61
+ }
62
+
56
63
  if (videoElement) {
57
64
  // TODO(2025-01-31): Remove these function guards.
58
65
  // Sentry has some error traces where "cancelVideoFrameCallback is not a function".
@@ -190,6 +197,7 @@
190
197
  return () =>
191
198
  untrack(() => {
192
199
  disableStream().then(() => {
200
+ pip.setStream(resourceName, null)
193
201
  setMediaStream(null)
194
202
  })
195
203
  })
@@ -301,7 +309,6 @@
301
309
  }
302
310
 
303
311
  const fps = useMeasureFps()
304
-
305
312
  $effect(() => {
306
313
  let id: number | undefined
307
314
 
@@ -393,6 +400,7 @@
393
400
  {#if showResolutionOptions && isLive}
394
401
  <MutationSection
395
402
  title="SetStreamOptions"
403
+ api="rdk:component:camera"
396
404
  description="Change the resolution of the live stream video feed"
397
405
  lastError={resolutionMutation.error}
398
406
  class="-m-4 mt-4"
@@ -135,6 +135,7 @@
135
135
 
136
136
  <ApiSection
137
137
  title="DiscoverResources"
138
+ api="rdk:service:discovery"
138
139
  class="relative"
139
140
  >
140
141
  <Query
@@ -0,0 +1,8 @@
1
+ import { EncoderPositionType, type EncoderProperties } from '@viamrobotics/sdk';
2
+ /**
3
+ * Picks the position type to request from an encoder based on its properties.
4
+ * @param properties - The encoder's reported properties, if loaded.
5
+ * @returns A single-element argument tuple for `getPosition`.
6
+ * @example getEncoderPositionArgs({ angleDegreesSupported: true }) // [EncoderPositionType.ANGLE_DEGREES]
7
+ */
8
+ export declare const getEncoderPositionArgs: (properties: EncoderProperties | undefined) => [EncoderPositionType];
@@ -0,0 +1,20 @@
1
+ import { EncoderPositionType } from '@viamrobotics/sdk';
2
+ /**
3
+ * Picks the position type to request from an encoder based on its properties.
4
+ * @param properties - The encoder's reported properties, if loaded.
5
+ * @returns A single-element argument tuple for `getPosition`.
6
+ * @example getEncoderPositionArgs({ angleDegreesSupported: true }) // [EncoderPositionType.ANGLE_DEGREES]
7
+ */
8
+ export const getEncoderPositionArgs = (properties) => {
9
+ if (!properties) {
10
+ return [EncoderPositionType.UNSPECIFIED];
11
+ }
12
+ const { angleDegreesSupported, ticksCountSupported } = properties;
13
+ if (angleDegreesSupported) {
14
+ return [EncoderPositionType.ANGLE_DEGREES];
15
+ }
16
+ if (ticksCountSupported) {
17
+ return [EncoderPositionType.TICKS_COUNT];
18
+ }
19
+ return [EncoderPositionType.UNSPECIFIED];
20
+ };
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { Button } from '@viamrobotics/prime-core'
3
- import { EncoderClient, EncoderPositionType, type EncoderProperties } from '@viamrobotics/sdk'
3
+ import { EncoderClient } from '@viamrobotics/sdk'
4
4
  import {
5
5
  createResourceClient,
6
6
  createResourceMutation,
@@ -14,6 +14,7 @@
14
14
  import RefetchController from '../../refetch-controller.svelte'
15
15
  import { createRefetchIntervalStore } from '../../refetch-interval-store.svelte'
16
16
 
17
+ import { getEncoderPositionArgs } from './encoder-position-type'
17
18
  import Position from './position.svelte'
18
19
 
19
20
  interface Props {
@@ -35,24 +36,6 @@
35
36
  'encoder-view'
36
37
  )
37
38
 
38
- const getPositionArgs = (properties: EncoderProperties | undefined): [EncoderPositionType] => {
39
- if (!properties) {
40
- return [EncoderPositionType.UNSPECIFIED]
41
- }
42
-
43
- const { angleDegreesSupported, ticksCountSupported } = properties
44
-
45
- if (angleDegreesSupported) {
46
- return [EncoderPositionType.ANGLE_DEGREES]
47
- }
48
-
49
- if (ticksCountSupported) {
50
- return [EncoderPositionType.TICKS_COUNT]
51
- }
52
-
53
- return [EncoderPositionType.UNSPECIFIED]
54
- }
55
-
56
39
  const propertiesQuery = createResourceQuery(client, 'getProperties', () => ({
57
40
  refetchInterval: refetchInterval.current,
58
41
  }))
@@ -60,7 +43,7 @@
60
43
  const positionQuery = createResourceQuery(
61
44
  client,
62
45
  'getPosition',
63
- () => getPositionArgs(propertiesQuery.data),
46
+ () => getEncoderPositionArgs(propertiesQuery.data),
64
47
  () => ({
65
48
  enabled: propertiesQuery.data !== undefined,
66
49
  refetchInterval: refetchInterval.current,
@@ -81,6 +64,7 @@
81
64
  <div class="grid w-full grid-cols-2 divide-x">
82
65
  <ApiSection
83
66
  title="GetPosition"
67
+ api="rdk:component:encoder"
84
68
  tooltip="Relative encoders return ticks since last zeroing. Absolute encoders return degrees."
85
69
  class="gap-3"
86
70
  >
@@ -99,6 +83,7 @@
99
83
 
100
84
  <ApiSection
101
85
  title="ResetPosition"
86
+ api="rdk:component:encoder"
102
87
  description="Set the current position as the new zero position"
103
88
  >
104
89
  <Button
@@ -0,0 +1,54 @@
1
+ <script lang="ts">
2
+ import { EncoderClient } from '@viamrobotics/sdk'
3
+ import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
4
+
5
+ import ApiSection from '../../api-section.svelte'
6
+ import Queries from '../../queries.svelte'
7
+
8
+ import { getEncoderPositionArgs } from './encoder-position-type'
9
+ import Position from './position.svelte'
10
+
11
+ interface Props {
12
+ partID: string
13
+ resourceName: string
14
+ }
15
+
16
+ const { partID, resourceName }: Props = $props()
17
+
18
+ const client = createResourceClient(
19
+ EncoderClient,
20
+ () => partID,
21
+ () => resourceName
22
+ )
23
+
24
+ const propertiesQuery = createResourceQuery(client, 'getProperties', { refetchInterval: 500 })
25
+
26
+ const positionQuery = createResourceQuery(
27
+ client,
28
+ 'getPosition',
29
+ () => getEncoderPositionArgs(propertiesQuery.data),
30
+ () => ({
31
+ enabled: propertiesQuery.data !== undefined,
32
+ refetchInterval: 500,
33
+ })
34
+ )
35
+ </script>
36
+
37
+ <ApiSection
38
+ title="GetPosition"
39
+ tooltip="Relative encoders return ticks since last zeroing. Absolute encoders return degrees."
40
+ bottomText="Updates automatically"
41
+ class="grow"
42
+ >
43
+ <Queries queries={[propertiesQuery, positionQuery]}>
44
+ {#if positionQuery.data !== undefined}
45
+ {@const [position, encoderPositionType] = positionQuery.data}
46
+ <div class="font-roboto-mono flex flex-col gap-2 text-sm">
47
+ <Position
48
+ {position}
49
+ {encoderPositionType}
50
+ />
51
+ </div>
52
+ {/if}
53
+ </Queries>
54
+ </ApiSection>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ partID: string;
3
+ resourceName: string;
4
+ }
5
+ declare const GetPositionWidget: import("svelte").Component<Props, {}, "">;
6
+ type GetPositionWidget = ReturnType<typeof GetPositionWidget>;
7
+ export default GetPositionWidget;
@@ -6,6 +6,7 @@
6
6
  createResourceQuery,
7
7
  } from '@viamrobotics/svelte-sdk'
8
8
 
9
+ import { apiDocsHref } from '../../../api-docs-href'
9
10
  import ApiSection from '../../api-section.svelte'
10
11
  import ConnectionStatus from '../../connection-status.svelte'
11
12
  import IsMoving from '../../is-moving.svelte'
@@ -51,12 +52,26 @@
51
52
  aria-labelledby={positionHeadingID}
52
53
  >
53
54
  <h3
54
- class="flex flex-row items-center gap-1 text-sm"
55
+ class="text-subtle-2 flex flex-row items-center gap-1 text-sm"
55
56
  id={positionHeadingID}
56
57
  >
57
- <span class="font-semibold"> GetPosition </span>
58
+ <a
59
+ href={apiDocsHref('rdk:component:gantry', 'getPosition')}
60
+ target="_blank"
61
+ rel="noopener noreferrer external"
62
+ class="decoration-gray-5 hover:decoration-default text-default font-mono font-semibold underline underline-offset-3"
63
+ >
64
+ GetPosition
65
+ </a>
58
66
  and
59
- <span class="font-semibold"> GetLengths </span>
67
+ <a
68
+ href={apiDocsHref('rdk:component:gantry', 'getLengths')}
69
+ target="_blank"
70
+ rel="noopener noreferrer external"
71
+ class="decoration-gray-5 hover:decoration-default text-default font-mono font-semibold underline underline-offset-3"
72
+ >
73
+ GetLengths
74
+ </a>
60
75
  </h3>
61
76
  <Queries queries={[positionQuery, lengthsQuery]}>
62
77
  {@const positions = positionQuery.data}
@@ -69,7 +84,10 @@
69
84
  {/if}
70
85
  </Queries>
71
86
  </ApiSection>
72
- <ApiSection title="MoveToPosition">
87
+ <ApiSection
88
+ title="MoveToPosition"
89
+ api="rdk:component:gantry"
90
+ >
73
91
  <Query query={positionQuery}>
74
92
  {@const positions = positionQuery.data}
75
93
  {#if positions !== undefined}
@@ -106,6 +124,7 @@
106
124
  </ApiSection>
107
125
  <ApiSection
108
126
  title="Home"
127
+ api="rdk:component:gantry"
109
128
  description="Run the homing sequence"
110
129
  >
111
130
  <Home
@@ -116,7 +135,10 @@
116
135
  </div>
117
136
  </div>
118
137
  <div class="ml-auto flex w-full max-w-40 flex-col divide-y">
119
- <ApiSection title="Stop">
138
+ <ApiSection
139
+ title="Stop"
140
+ api="rdk:component:gantry"
141
+ >
120
142
  <StopButton
121
143
  error={stopMutation.error}
122
144
  onStop={() => {
@@ -126,6 +148,7 @@
126
148
  </ApiSection>
127
149
  <IsMoving
128
150
  client={GantryClient}
151
+ api="rdk:component:gantry"
129
152
  {partID}
130
153
  {resourceName}
131
154
  />
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { GantryClient } from '@viamrobotics/sdk'
3
+ import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
4
+
5
+ import ApiSection from '../../api-section.svelte'
6
+ import Queries from '../../queries.svelte'
7
+
8
+ import PositionAndLengths from './position-and-lengths.svelte'
9
+
10
+ interface Props {
11
+ partID: string
12
+ resourceName: string
13
+ }
14
+
15
+ const { partID, resourceName }: Props = $props()
16
+
17
+ const client = createResourceClient(
18
+ GantryClient,
19
+ () => partID,
20
+ () => resourceName
21
+ )
22
+
23
+ const options = { refetchInterval: 500 }
24
+ const positionQuery = createResourceQuery(client, 'getPosition', options)
25
+ const lengthsQuery = createResourceQuery(client, 'getLengths', options)
26
+ </script>
27
+
28
+ <ApiSection
29
+ title="GetPosition"
30
+ bottomText="Updates automatically"
31
+ class="grow"
32
+ >
33
+ <Queries queries={[positionQuery, lengthsQuery]}>
34
+ {@const positions = positionQuery.data}
35
+ {@const lengths = lengthsQuery.data ?? []}
36
+ {#if positions !== undefined}
37
+ <PositionAndLengths
38
+ {positions}
39
+ {lengths}
40
+ />
41
+ {/if}
42
+ </Queries>
43
+ </ApiSection>
@@ -0,0 +1,7 @@
1
+ interface Props {
2
+ partID: string;
3
+ resourceName: string;
4
+ }
5
+ declare const GetPositionWidget: import("svelte").Component<Props, {}, "">;
6
+ type GetPositionWidget = ReturnType<typeof GetPositionWidget>;
7
+ export default GetPositionWidget;