@viamrobotics/motion-tools 0.14.0 → 0.14.2
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.
- package/dist/components/Details.svelte +31 -26
- package/dist/components/SceneProviders.svelte +2 -0
- package/dist/components/Tree/AddFrames.svelte +7 -5
- package/dist/components/Tree/Tree.svelte +1 -4
- package/dist/hooks/useFrames.svelte.js +2 -4
- package/dist/hooks/usePartConfig.svelte.js +21 -16
- package/dist/hooks/usePose.svelte.js +7 -0
- package/package.json +1 -1
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<script lang="ts">
|
|
14
14
|
import { Check, Copy } from 'lucide-svelte'
|
|
15
15
|
import { useTask } from '@threlte/core'
|
|
16
|
-
import { Button, Icon } from '@viamrobotics/prime-core'
|
|
16
|
+
import { Button, Icon, Select, Input } from '@viamrobotics/prime-core'
|
|
17
17
|
import {
|
|
18
18
|
useSelectedObject,
|
|
19
19
|
useFocusedObject,
|
|
@@ -106,15 +106,18 @@
|
|
|
106
106
|
value,
|
|
107
107
|
ariaLabel,
|
|
108
108
|
}: {
|
|
109
|
-
label
|
|
109
|
+
label?: string
|
|
110
110
|
value: string
|
|
111
111
|
ariaLabel: string
|
|
112
112
|
})}
|
|
113
113
|
<div>
|
|
114
114
|
<span
|
|
115
115
|
class="text-subtle-2"
|
|
116
|
-
aria-label={`immutable ${ariaLabel}`}
|
|
116
|
+
aria-label={`immutable ${ariaLabel}`}
|
|
117
117
|
>
|
|
118
|
+
{label}
|
|
119
|
+
</span>
|
|
120
|
+
|
|
118
121
|
{value}
|
|
119
122
|
</div>
|
|
120
123
|
{/snippet}
|
|
@@ -130,14 +133,16 @@
|
|
|
130
133
|
ariaLabel: string
|
|
131
134
|
onInput: (value: string) => void
|
|
132
135
|
})}
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
<div class="flex items-center gap-1">
|
|
137
|
+
<span class="text-subtle-2">{label}</span>
|
|
138
|
+
<Input
|
|
139
|
+
type="number"
|
|
140
|
+
aria-label={`mutable ${ariaLabel}`}
|
|
141
|
+
class="max-w-24 min-w-0 flex-1 rounded border px-1 py-0.5 text-xs"
|
|
142
|
+
{value}
|
|
143
|
+
on:input={(event) => onInput((event.target as HTMLInputElement).value)}
|
|
144
|
+
/>
|
|
145
|
+
</div>
|
|
141
146
|
{/snippet}
|
|
142
147
|
|
|
143
148
|
{#snippet DropDownField({
|
|
@@ -151,16 +156,17 @@
|
|
|
151
156
|
options: string[]
|
|
152
157
|
onChange: (value: string) => void
|
|
153
158
|
})}
|
|
154
|
-
<
|
|
159
|
+
<Select
|
|
155
160
|
aria-label={`dropdown ${ariaLabel}`}
|
|
156
|
-
class="w-full rounded border border-gray-300 px-2 py-1 text-sm"
|
|
157
161
|
{value}
|
|
158
|
-
onchange={(
|
|
162
|
+
onchange={(event: InputEvent) => {
|
|
163
|
+
onChange((event.target as HTMLSelectElement).value)
|
|
164
|
+
}}
|
|
159
165
|
>
|
|
160
166
|
{#each options as option (option)}
|
|
161
167
|
<option value={option}>{option}</option>
|
|
162
168
|
{/each}
|
|
163
|
-
</
|
|
169
|
+
</Select>
|
|
164
170
|
{/snippet}
|
|
165
171
|
|
|
166
172
|
{#if object}
|
|
@@ -259,7 +265,6 @@
|
|
|
259
265
|
<strong class="font-semibold">parent frame</strong>
|
|
260
266
|
<div class="flex gap-3">
|
|
261
267
|
{@render ParentFrame({
|
|
262
|
-
label: 'name',
|
|
263
268
|
ariaLabel: 'parent frame name',
|
|
264
269
|
value: referenceFrame,
|
|
265
270
|
options: referenceFrameOptions,
|
|
@@ -494,16 +499,6 @@
|
|
|
494
499
|
|
|
495
500
|
<h3 class="text-subtle-2 pt-3 pb-2">Actions</h3>
|
|
496
501
|
|
|
497
|
-
<WeblabActive experiment="MOTION_TOOLS_EDIT_FRAME">
|
|
498
|
-
{#if isFrameNode}
|
|
499
|
-
<Button
|
|
500
|
-
variant="danger"
|
|
501
|
-
class="mb-2 w-full"
|
|
502
|
-
onclick={() => detailConfigUpdater.deleteFrame()}>Delete Frame</Button
|
|
503
|
-
>
|
|
504
|
-
{/if}
|
|
505
|
-
</WeblabActive>
|
|
506
|
-
|
|
507
502
|
{#if focused.current}
|
|
508
503
|
<Button
|
|
509
504
|
class="w-full"
|
|
@@ -522,5 +517,15 @@
|
|
|
522
517
|
Enter object view
|
|
523
518
|
</Button>
|
|
524
519
|
{/if}
|
|
520
|
+
|
|
521
|
+
<WeblabActive experiment="MOTION_TOOLS_EDIT_FRAME">
|
|
522
|
+
{#if isFrameNode}
|
|
523
|
+
<Button
|
|
524
|
+
variant="danger"
|
|
525
|
+
class="mt-2 w-full"
|
|
526
|
+
onclick={() => detailConfigUpdater.deleteFrame()}>Delete Frame</Button
|
|
527
|
+
>
|
|
528
|
+
{/if}
|
|
529
|
+
</WeblabActive>
|
|
525
530
|
</div>
|
|
526
531
|
{/if}
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
import { provideWorldStates } from '../hooks/useWorldState.svelte'
|
|
18
18
|
import { provideArmClient } from '../hooks/useArmClient.svelte'
|
|
19
19
|
import { provideArrows } from '../hooks/useArrows.svelte'
|
|
20
|
+
import { provideFramelessComponents } from '../hooks/useFramelessComponents.svelte'
|
|
20
21
|
interface Props {
|
|
21
22
|
children: Snippet<[{ focus: boolean }]>
|
|
22
23
|
}
|
|
@@ -42,6 +43,7 @@
|
|
|
42
43
|
provideObjects()
|
|
43
44
|
provideWorldStates()
|
|
44
45
|
provideArmClient(() => partID.current)
|
|
46
|
+
provideFramelessComponents()
|
|
45
47
|
|
|
46
48
|
const { focus } = provideSelection()
|
|
47
49
|
</script>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { IconButton } from '@viamrobotics/prime-core'
|
|
2
3
|
import Drawer from './Drawer.svelte'
|
|
3
4
|
import { usePartConfig } from '../../hooks/usePartConfig.svelte'
|
|
4
5
|
import { useFramelessComponents } from '../../hooks/useFramelessComponents.svelte'
|
|
@@ -12,12 +13,13 @@
|
|
|
12
13
|
{#if framelessComponents.current.length > 0}
|
|
13
14
|
<ul class="space-y-1">
|
|
14
15
|
{#each framelessComponents.current as component (component)}
|
|
15
|
-
<li class="text-
|
|
16
|
+
<li class="flex items-center gap-2 text-xs text-gray-700">
|
|
16
17
|
{component}
|
|
17
|
-
<
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
<IconButton
|
|
19
|
+
label="Add frame"
|
|
20
|
+
icon="plus"
|
|
21
|
+
onclick={() => partConfig.createFrame(component)}
|
|
22
|
+
/>
|
|
21
23
|
</li>
|
|
22
24
|
{/each}
|
|
23
25
|
</ul>
|
|
@@ -156,10 +156,7 @@
|
|
|
156
156
|
<h3 {...api.getLabelProps() as object}>{rootNode.name}</h3>
|
|
157
157
|
</div>
|
|
158
158
|
|
|
159
|
-
<div
|
|
160
|
-
{...api.getTreeProps()}
|
|
161
|
-
class="w-60"
|
|
162
|
-
>
|
|
159
|
+
<div {...api.getTreeProps()}>
|
|
163
160
|
{#if rootChildren.length === 0}
|
|
164
161
|
<p class="text-subtle-2 px-2 py-4">No objects displayed</p>
|
|
165
162
|
{:else if rootChildren.length > 200}
|
|
@@ -19,10 +19,8 @@ export const provideFrames = (partID) => {
|
|
|
19
19
|
const partConfig = usePartConfig();
|
|
20
20
|
const environment = useEnvironment();
|
|
21
21
|
observe.pre(() => [revision], () => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
logs.add('Fetching frames...');
|
|
25
|
-
}
|
|
22
|
+
untrack(() => query.current).refetch();
|
|
23
|
+
logs.add('Fetching frames...');
|
|
26
24
|
});
|
|
27
25
|
observe.pre(() => [partConfig.isDirty], () => {
|
|
28
26
|
if (partConfig.isDirty) {
|
|
@@ -254,30 +254,35 @@ export class StandalonePartConfig {
|
|
|
254
254
|
this._localPartConfig = Struct.fromJson(configJson);
|
|
255
255
|
this._partName = partResponse?.part?.name;
|
|
256
256
|
const componentNameToFragmentId = {};
|
|
257
|
-
const
|
|
257
|
+
const fragmentRequests = [];
|
|
258
258
|
if (configJson.fragments) {
|
|
259
259
|
for (const fragmentId of configJson.fragments) {
|
|
260
|
-
|
|
260
|
+
fragmentRequests.push(standalonePartConfigProps.viamClient()?.appClient.getFragment(fragmentId));
|
|
261
261
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
262
|
+
try {
|
|
263
|
+
const fragementResponses = await Promise.all(fragmentRequests);
|
|
264
|
+
for (const fragmentResponse of fragementResponses) {
|
|
265
|
+
const fragmentId = fragmentResponse?.id;
|
|
266
|
+
if (!fragmentId) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const components = fragmentResponse?.fragment?.fields['components'].kind;
|
|
270
|
+
if (components?.case === 'listValue') {
|
|
271
|
+
for (const component of components.value.values) {
|
|
272
|
+
if (component.kind.case === 'structValue') {
|
|
273
|
+
const componentName = component.kind.value.fields['name'].kind;
|
|
274
|
+
if (componentName.case === 'stringValue') {
|
|
275
|
+
componentNameToFragmentId[componentName.value] = fragmentId;
|
|
276
|
+
}
|
|
275
277
|
}
|
|
276
278
|
}
|
|
277
279
|
}
|
|
278
280
|
}
|
|
281
|
+
this._componentNameToFragmentId = componentNameToFragmentId;
|
|
282
|
+
}
|
|
283
|
+
catch {
|
|
284
|
+
/* Do nothing */
|
|
279
285
|
}
|
|
280
|
-
this._componentNameToFragmentId = componentNameToFragmentId;
|
|
281
286
|
}
|
|
282
287
|
};
|
|
283
288
|
initLocalConfig();
|
|
@@ -6,6 +6,8 @@ import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
|
|
|
6
6
|
import { fromStore, toStore } from 'svelte/store';
|
|
7
7
|
import { useMotionClient } from './useMotionClient.svelte';
|
|
8
8
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
9
|
+
import { observe } from '@threlte/core';
|
|
10
|
+
import { untrack } from 'svelte';
|
|
9
11
|
export const usePose = (name, parent) => {
|
|
10
12
|
const { refreshRates } = useMachineSettings();
|
|
11
13
|
const partID = usePartID();
|
|
@@ -40,6 +42,11 @@ export const usePose = (name, parent) => {
|
|
|
40
42
|
},
|
|
41
43
|
}));
|
|
42
44
|
const query = fromStore(createQuery(toStore(() => options)));
|
|
45
|
+
observe.pre(() => [environment.current.viewerMode], () => {
|
|
46
|
+
if (environment.current.viewerMode === 'monitor') {
|
|
47
|
+
untrack(() => query.current).refetch();
|
|
48
|
+
}
|
|
49
|
+
});
|
|
43
50
|
return {
|
|
44
51
|
get current() {
|
|
45
52
|
if (resource?.subtype === 'arm') {
|