tassello 0.1.0 → 0.2.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.
- package/CHANGELOG.md +26 -0
- package/README.md +66 -3
- package/dist/server/behavior_tree_file.d.ts +17 -0
- package/dist/server/behavior_tree_file.js +232 -0
- package/dist/server/behavior_tree_files.d.ts +18 -0
- package/dist/server/behavior_tree_files.js +405 -0
- package/dist/server/behavior_tree_log.d.ts +10 -0
- package/dist/server/behavior_tree_log.js +132 -0
- package/dist/server/behavior_tree_playback.d.ts +57 -0
- package/dist/server/behavior_tree_playback.js +188 -0
- package/dist/server/behavior_tree_state.d.ts +38 -0
- package/dist/server/behavior_tree_state.js +220 -0
- package/dist/server/behavior_trees.d.ts +29 -0
- package/dist/server/behavior_trees.js +362 -0
- package/dist/server/files.d.ts +5 -2
- package/dist/server/files.js +32 -13
- package/dist/server/http.js +7 -5
- package/dist/server/rosbag.d.ts +25 -0
- package/dist/server/rosbag.js +418 -0
- package/dist/server/rosout.d.ts +16 -0
- package/dist/server/rosout.js +203 -0
- package/dist/server/rosout_log.d.ts +20 -0
- package/dist/server/rosout_log.js +66 -0
- package/dist/server/server.js +20 -4
- package/dist/server/session.d.ts +7 -0
- package/dist/server/session.js +63 -0
- package/dist/server/systemd.js +1 -1
- package/dist/server/systemd_format.d.ts +1 -0
- package/dist/server/systemd_format.js +19 -3
- package/dist/shared/bt_nodes.d.ts +25 -0
- package/dist/shared/bt_nodes.js +180 -0
- package/dist/shared/protocol.d.ts +157 -2
- package/dist/shared/protocol.js +4 -0
- package/dist/shared/xml.d.ts +25 -0
- package/dist/shared/xml.js +164 -0
- package/dist/types/client/api.d.ts +4 -3
- package/dist/types/client/connection.d.ts +31 -1
- package/dist/types/client/dialogs.d.ts +2 -1
- package/dist/types/client/icons.d.ts +24 -0
- package/dist/types/client/sdk/index.d.ts +3 -2
- package/dist/types/client/widgets/types.d.ts +5 -1
- package/dist/types/shared/bt_nodes.d.ts +25 -0
- package/dist/types/shared/protocol.d.ts +157 -2
- package/dist/www/assets/Joystick.js +1 -1
- package/dist/www/assets/RobotModelView.js +2 -2
- package/dist/www/assets/icons.js +1 -1
- package/dist/www/assets/index.css +1 -1
- package/dist/www/assets/index.js +28 -1
- package/dist/www/assets/shared/tassello-sdk.js +1 -1
- package/docs/plugins.md +8 -0
- package/package.json +2 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { BtNodeModel } from './bt_nodes.ts';
|
|
1
2
|
export type ImageTransport = 'auto' | 'raw' | 'compressed';
|
|
2
3
|
export type GridStyle = 'map' | 'costmap';
|
|
3
4
|
export interface TwistCommand {
|
|
@@ -146,7 +147,52 @@ export interface PluginSubscribe {
|
|
|
146
147
|
stream: string;
|
|
147
148
|
params: unknown;
|
|
148
149
|
}
|
|
149
|
-
export
|
|
150
|
+
export interface BehaviorTreeSubscribe {
|
|
151
|
+
type: 'bt.subscribe';
|
|
152
|
+
id: number;
|
|
153
|
+
topic: string;
|
|
154
|
+
tree: string;
|
|
155
|
+
}
|
|
156
|
+
export interface BehaviorTreeRecord {
|
|
157
|
+
type: 'bt.record';
|
|
158
|
+
id: number;
|
|
159
|
+
topic: string;
|
|
160
|
+
path: string | null;
|
|
161
|
+
}
|
|
162
|
+
export interface BehaviorTreePlaybackSubscribe {
|
|
163
|
+
type: 'bt.playback';
|
|
164
|
+
id: number;
|
|
165
|
+
bag: string;
|
|
166
|
+
topic: string;
|
|
167
|
+
tree: string;
|
|
168
|
+
}
|
|
169
|
+
export interface BehaviorTreePlaybackControl {
|
|
170
|
+
type: 'bt.playback.control';
|
|
171
|
+
id: number;
|
|
172
|
+
playing?: boolean;
|
|
173
|
+
speed?: number;
|
|
174
|
+
time?: number;
|
|
175
|
+
}
|
|
176
|
+
export interface BehaviorTreeFileSubscribe {
|
|
177
|
+
type: 'bt.file.subscribe';
|
|
178
|
+
id: number;
|
|
179
|
+
path: string;
|
|
180
|
+
libraries: string[];
|
|
181
|
+
}
|
|
182
|
+
export interface BehaviorTreeFileSave {
|
|
183
|
+
type: 'bt.file.save';
|
|
184
|
+
id: number;
|
|
185
|
+
path: string;
|
|
186
|
+
text: string;
|
|
187
|
+
base: string | null;
|
|
188
|
+
create: boolean;
|
|
189
|
+
}
|
|
190
|
+
export interface RosoutSubscribe {
|
|
191
|
+
type: 'rosout.subscribe';
|
|
192
|
+
id: number;
|
|
193
|
+
topic: string;
|
|
194
|
+
}
|
|
195
|
+
export type ClientMessage = TwistCommand | ImageSubscribe | GridSubscribe | TfSubscribe | PathSubscribe | TopicSubscribe | ServicesSubscribe | ServiceAction | LogsSubscribe | Unsubscribe | FrameAck | PosePublish | CommandRun | CommandStop | ArmSubscribe | ArmJog | RosPublish | RosCall | PluginRequest | PluginSubscribe | BehaviorTreeSubscribe | BehaviorTreeRecord | BehaviorTreePlaybackSubscribe | BehaviorTreePlaybackControl | BehaviorTreeFileSubscribe | BehaviorTreeFileSave | RosoutSubscribe;
|
|
150
196
|
export interface Hello {
|
|
151
197
|
type: 'hello';
|
|
152
198
|
clientId: string;
|
|
@@ -277,7 +323,113 @@ export interface PluginData {
|
|
|
277
323
|
id: number;
|
|
278
324
|
data: unknown;
|
|
279
325
|
}
|
|
280
|
-
export type
|
|
326
|
+
export type BtNodeKind = 'action' | 'condition' | 'control' | 'decorator' | 'subtree';
|
|
327
|
+
export interface BtNode {
|
|
328
|
+
name: string;
|
|
329
|
+
type: string;
|
|
330
|
+
kind: BtNodeKind | null;
|
|
331
|
+
parent: number;
|
|
332
|
+
ports: Record<string, string>;
|
|
333
|
+
}
|
|
334
|
+
export interface BehaviorTreeInfo {
|
|
335
|
+
type: 'bt.tree';
|
|
336
|
+
id: number;
|
|
337
|
+
treeId: string;
|
|
338
|
+
nodes: BtNode[];
|
|
339
|
+
error: string | null;
|
|
340
|
+
warnings: string[];
|
|
341
|
+
}
|
|
342
|
+
export interface BtNodeState {
|
|
343
|
+
node: number;
|
|
344
|
+
status: string | null;
|
|
345
|
+
result: string | null;
|
|
346
|
+
since: number;
|
|
347
|
+
changes: number;
|
|
348
|
+
successes: number;
|
|
349
|
+
failures: number;
|
|
350
|
+
}
|
|
351
|
+
export interface BtTransition {
|
|
352
|
+
time: number;
|
|
353
|
+
node: number;
|
|
354
|
+
from: string;
|
|
355
|
+
to: string;
|
|
356
|
+
}
|
|
357
|
+
export interface BehaviorTreeRecording {
|
|
358
|
+
type: 'bt.recording';
|
|
359
|
+
id: number;
|
|
360
|
+
recording: {
|
|
361
|
+
path: string;
|
|
362
|
+
since: number;
|
|
363
|
+
} | null;
|
|
364
|
+
}
|
|
365
|
+
export interface BehaviorTreePlaybackState {
|
|
366
|
+
type: 'bt.playback.state';
|
|
367
|
+
id: number;
|
|
368
|
+
topic: string;
|
|
369
|
+
start: number;
|
|
370
|
+
end: number;
|
|
371
|
+
time: number;
|
|
372
|
+
playing: boolean;
|
|
373
|
+
speed: number;
|
|
374
|
+
error: string | null;
|
|
375
|
+
}
|
|
376
|
+
export interface BehaviorTreeUpdate {
|
|
377
|
+
type: 'bt';
|
|
378
|
+
id: number;
|
|
379
|
+
reset: boolean;
|
|
380
|
+
added: BtNode[];
|
|
381
|
+
states: BtNodeState[];
|
|
382
|
+
transitions: BtTransition[];
|
|
383
|
+
mismatch: string | null;
|
|
384
|
+
}
|
|
385
|
+
export interface BehaviorTreeFile {
|
|
386
|
+
type: 'bt.file';
|
|
387
|
+
id: number;
|
|
388
|
+
file: string;
|
|
389
|
+
text: string | null;
|
|
390
|
+
version: string | null;
|
|
391
|
+
readOnly: string | null;
|
|
392
|
+
error: string | null;
|
|
393
|
+
}
|
|
394
|
+
export interface BtNodeLibrary {
|
|
395
|
+
name: string;
|
|
396
|
+
file: string;
|
|
397
|
+
models: BtNodeModel[];
|
|
398
|
+
}
|
|
399
|
+
export interface BehaviorTreeModels {
|
|
400
|
+
type: 'bt.models';
|
|
401
|
+
id: number;
|
|
402
|
+
libraries: BtNodeLibrary[];
|
|
403
|
+
trees: {
|
|
404
|
+
id: string;
|
|
405
|
+
file: string;
|
|
406
|
+
}[];
|
|
407
|
+
warnings: string[];
|
|
408
|
+
}
|
|
409
|
+
export interface BehaviorTreeSaved {
|
|
410
|
+
version: string;
|
|
411
|
+
conflict: boolean;
|
|
412
|
+
}
|
|
413
|
+
export interface LogEntry {
|
|
414
|
+
seq: number;
|
|
415
|
+
stamp: number;
|
|
416
|
+
level: number;
|
|
417
|
+
name: string;
|
|
418
|
+
msg: string;
|
|
419
|
+
file: string;
|
|
420
|
+
function: string;
|
|
421
|
+
line: number;
|
|
422
|
+
}
|
|
423
|
+
export interface RosoutUpdate {
|
|
424
|
+
type: 'rosout';
|
|
425
|
+
id: number;
|
|
426
|
+
reset: boolean;
|
|
427
|
+
started: number;
|
|
428
|
+
entries: LogEntry[];
|
|
429
|
+
skipped: number;
|
|
430
|
+
nodes: string[] | null;
|
|
431
|
+
}
|
|
432
|
+
export type ServerMessage = Hello | CommandStates | CommandUpdate | StreamStatus | TfUpdate | PathUpdate | TopicMessage | ServicesUpdate | ServiceResult | LogsUpdate | ArmUpdate | Result | PluginData | BehaviorTreeInfo | BehaviorTreeUpdate | BehaviorTreeRecording | BehaviorTreePlaybackState | BehaviorTreeFile | BehaviorTreeModels | RosoutUpdate | PanelsChanged | ErrorMessage;
|
|
281
433
|
export declare const FRAME_HEADER_BYTES = 11;
|
|
282
434
|
export declare const IMAGE_FORMATS: readonly ['image/jpeg', 'image/png'];
|
|
283
435
|
export interface GridInfo {
|
|
@@ -297,6 +449,9 @@ export interface GridInfo {
|
|
|
297
449
|
}
|
|
298
450
|
export declare const TELEOP_WATCHDOG_MS = 500;
|
|
299
451
|
export declare const ARM_STATE_RATE = 10;
|
|
452
|
+
export declare const BT_RATE = 10;
|
|
453
|
+
export declare const ROSOUT_RATE = 10;
|
|
454
|
+
export declare const ROSOUT_HISTORY = 10000;
|
|
300
455
|
export declare const DASHBOARD_CLIENT_HEADER = "X-Dashboard-Client";
|
|
301
456
|
export interface PluginInfo {
|
|
302
457
|
name: string;
|
package/dist/shared/protocol.js
CHANGED
|
@@ -15,4 +15,8 @@ export const FRAME_HEADER_BYTES = 11;
|
|
|
15
15
|
export const IMAGE_FORMATS = ['image/jpeg', 'image/png'];
|
|
16
16
|
export const TELEOP_WATCHDOG_MS = 500;
|
|
17
17
|
export const ARM_STATE_RATE = 10;
|
|
18
|
+
export const BT_RATE = 10;
|
|
19
|
+
export const ROSOUT_RATE = 10;
|
|
20
|
+
// Messages of the ROS log kept by the server, and by the page
|
|
21
|
+
export const ROSOUT_HISTORY = 10_000;
|
|
18
22
|
export const DASHBOARD_CLIENT_HEADER = 'X-Dashboard-Client';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export interface XmlElement {
|
|
2
|
+
name: string;
|
|
3
|
+
attributes: Record<string, string>;
|
|
4
|
+
children: XmlElement[];
|
|
5
|
+
line: number;
|
|
6
|
+
}
|
|
7
|
+
export interface SourceElement {
|
|
8
|
+
type: 'element';
|
|
9
|
+
name: string;
|
|
10
|
+
attributes: Record<string, string>;
|
|
11
|
+
children: SourceNode[];
|
|
12
|
+
line: number;
|
|
13
|
+
start: number;
|
|
14
|
+
openEnd: number;
|
|
15
|
+
end: number;
|
|
16
|
+
}
|
|
17
|
+
export interface SourceMarkup {
|
|
18
|
+
type: 'comment' | 'text';
|
|
19
|
+
start: number;
|
|
20
|
+
end: number;
|
|
21
|
+
}
|
|
22
|
+
export type SourceNode = SourceElement | SourceMarkup;
|
|
23
|
+
export declare function parseXmlSource(text: string): SourceElement;
|
|
24
|
+
export declare function sourceText(text: string, element: SourceElement): string;
|
|
25
|
+
export declare function parseXml(text: string): XmlElement;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// A small XML reader, for the behavior trees' files. BT.CPP's XML is made of
|
|
2
|
+
// elements and attributes, which is what parseXml gives: the server reads
|
|
3
|
+
// the trees with it. parseXmlSource also keeps the comments and text, and
|
|
4
|
+
// where each node is in the text: the behavior tree editor writes a file
|
|
5
|
+
// back as it was, but for what it changed. No DOM: the server has none.
|
|
6
|
+
const START_TAG = /<([A-Za-z_:][-\w:.]*)((?:\s+[A-Za-z_:][-\w:.]*\s*=\s*(?:"[^"]*"|'[^']*'))*)\s*(\/?)>/y;
|
|
7
|
+
const END_TAG = /<\/([A-Za-z_:][-\w:.]*)\s*>/y;
|
|
8
|
+
const ATTRIBUTE = /([A-Za-z_:][-\w:.]*)\s*=\s*(?:"([^"]*)"|'([^']*)')/g;
|
|
9
|
+
const ENTITY = /&(?:(lt|gt|amp|quot|apos)|#(\d+)|#x([0-9A-Fa-f]+));/g;
|
|
10
|
+
const NAMED = { lt: '<', gt: '>', amp: '&', quot: '"', apos: "'" };
|
|
11
|
+
function decode(value) {
|
|
12
|
+
return value.replace(ENTITY, (entity, name, decimal, hex) => {
|
|
13
|
+
if (name) {
|
|
14
|
+
return NAMED[name];
|
|
15
|
+
}
|
|
16
|
+
const code = decimal ? Number(decimal) : parseInt(hex, 16);
|
|
17
|
+
return code <= 0x10ffff ? String.fromCodePoint(code) : entity;
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
// The document's root element, as written; throws, naming the line, if it
|
|
21
|
+
// is not XML
|
|
22
|
+
export function parseXmlSource(text) {
|
|
23
|
+
const newlines = [];
|
|
24
|
+
for (let i = text.indexOf('\n'); i !== -1; i = text.indexOf('\n', i + 1)) {
|
|
25
|
+
newlines.push(i);
|
|
26
|
+
}
|
|
27
|
+
const lineAt = (index) => {
|
|
28
|
+
let [low, high] = [0, newlines.length];
|
|
29
|
+
while (low < high) {
|
|
30
|
+
const middle = (low + high) >> 1;
|
|
31
|
+
if (newlines[middle] < index) {
|
|
32
|
+
low = middle + 1;
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
high = middle;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return low + 1;
|
|
39
|
+
};
|
|
40
|
+
const fail = (index, message) => {
|
|
41
|
+
throw new Error(`Line ${lineAt(index)}: ${message}`);
|
|
42
|
+
};
|
|
43
|
+
// Skips to after the terminator, which must come
|
|
44
|
+
const skip = (index, terminator, what) => {
|
|
45
|
+
const end = text.indexOf(terminator, index);
|
|
46
|
+
return end === -1 ? fail(index, `${what} not closed`) : end + terminator.length;
|
|
47
|
+
};
|
|
48
|
+
let root = null;
|
|
49
|
+
const open = [];
|
|
50
|
+
// Of the element open, if any
|
|
51
|
+
const add = (type, start, end) => open.at(-1)?.children.push({ type, start, end });
|
|
52
|
+
let i = 0;
|
|
53
|
+
while (i < text.length) {
|
|
54
|
+
const tag = text.indexOf('<', i);
|
|
55
|
+
// Text up to it, without its whitespace
|
|
56
|
+
const until = tag === -1 ? text.length : tag;
|
|
57
|
+
const textStart = text.slice(i, until).search(/\S/);
|
|
58
|
+
if (textStart !== -1) {
|
|
59
|
+
add('text', i + textStart, i + text.slice(i, until).trimEnd().length);
|
|
60
|
+
}
|
|
61
|
+
if (tag === -1) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
i = tag;
|
|
65
|
+
if (text.startsWith('<!--', i)) {
|
|
66
|
+
i = skip(i + 4, '-->', 'Comment');
|
|
67
|
+
add('comment', tag, i);
|
|
68
|
+
}
|
|
69
|
+
else if (text.startsWith('<![CDATA[', i)) {
|
|
70
|
+
i = skip(i + 9, ']]>', 'CDATA section');
|
|
71
|
+
add('text', tag, i);
|
|
72
|
+
}
|
|
73
|
+
else if (text.startsWith('<?', i)) {
|
|
74
|
+
i = skip(i + 2, '?>', 'Processing instruction');
|
|
75
|
+
add('comment', tag, i);
|
|
76
|
+
}
|
|
77
|
+
else if (text.startsWith('<!', i)) {
|
|
78
|
+
// A doctype, maybe with an internal subset in brackets
|
|
79
|
+
let depth = 0;
|
|
80
|
+
let j = i + 2;
|
|
81
|
+
for (; j < text.length && (text[j] !== '>' || depth > 0); j++) {
|
|
82
|
+
depth += text[j] === '[' ? 1 : text[j] === ']' ? -1 : 0;
|
|
83
|
+
}
|
|
84
|
+
i = j < text.length ? j + 1 : fail(i, 'Doctype not closed');
|
|
85
|
+
add('comment', tag, i);
|
|
86
|
+
}
|
|
87
|
+
else if (text[i + 1] === '/') {
|
|
88
|
+
END_TAG.lastIndex = i;
|
|
89
|
+
const end = END_TAG.exec(text) ?? fail(i, 'Malformed end tag');
|
|
90
|
+
const element = open.pop();
|
|
91
|
+
if (element?.name !== end[1]) {
|
|
92
|
+
fail(i, element ? `</${end[1]}> closes <${element.name}> of line ${element.line}` : `</${end[1]}> closes nothing`);
|
|
93
|
+
}
|
|
94
|
+
i = END_TAG.lastIndex;
|
|
95
|
+
element.end = i;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
START_TAG.lastIndex = i;
|
|
99
|
+
const start = START_TAG.exec(text) ?? fail(i, 'Malformed tag');
|
|
100
|
+
const attributes = {};
|
|
101
|
+
for (const match of start[2].matchAll(ATTRIBUTE)) {
|
|
102
|
+
attributes[match[1]] = decode(match[2] ?? match[3]);
|
|
103
|
+
}
|
|
104
|
+
const selfClosing = start[3] === '/';
|
|
105
|
+
const element = {
|
|
106
|
+
type: 'element',
|
|
107
|
+
name: start[1],
|
|
108
|
+
attributes,
|
|
109
|
+
children: [],
|
|
110
|
+
line: lineAt(i),
|
|
111
|
+
start: i,
|
|
112
|
+
openEnd: START_TAG.lastIndex - (selfClosing ? 2 : 1),
|
|
113
|
+
end: START_TAG.lastIndex,
|
|
114
|
+
};
|
|
115
|
+
const parent = open.at(-1);
|
|
116
|
+
if (parent) {
|
|
117
|
+
parent.children.push(element);
|
|
118
|
+
}
|
|
119
|
+
else if (root) {
|
|
120
|
+
fail(i, `<${element.name}> after the root element`);
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
root = element;
|
|
124
|
+
}
|
|
125
|
+
if (!selfClosing) {
|
|
126
|
+
open.push(element);
|
|
127
|
+
}
|
|
128
|
+
i = START_TAG.lastIndex;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (open.length > 0) {
|
|
132
|
+
const element = open.at(-1);
|
|
133
|
+
throw new Error(`Line ${element.line}: <${element.name}> not closed`);
|
|
134
|
+
}
|
|
135
|
+
if (!root) {
|
|
136
|
+
throw new Error('No XML element');
|
|
137
|
+
}
|
|
138
|
+
return root;
|
|
139
|
+
}
|
|
140
|
+
// The text of an element's text children, its entities decoded
|
|
141
|
+
export function sourceText(text, element) {
|
|
142
|
+
return element.children
|
|
143
|
+
.flatMap((child) => {
|
|
144
|
+
if (child.type !== 'text') {
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
const raw = text.slice(child.start, child.end);
|
|
148
|
+
return [raw.startsWith('<![CDATA[') ? raw.slice(9, -3) : decode(raw)];
|
|
149
|
+
})
|
|
150
|
+
.join(' ');
|
|
151
|
+
}
|
|
152
|
+
function elements(element) {
|
|
153
|
+
return {
|
|
154
|
+
name: element.name,
|
|
155
|
+
attributes: element.attributes,
|
|
156
|
+
children: element.children.flatMap((child) => (child.type === 'element' ? [elements(child)] : [])),
|
|
157
|
+
line: element.line,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// The document's root element: its elements and attributes, the rest
|
|
161
|
+
// skipped; throws, naming the line, if it is not XML
|
|
162
|
+
export function parseXml(text) {
|
|
163
|
+
return elements(parseXmlSource(text));
|
|
164
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { Panel, PanelSummary, TopicInfo } from '../shared/panel.ts';
|
|
2
2
|
import { type PluginInfo } from '../shared/protocol.ts';
|
|
3
|
+
export type FileKind = 'image' | 'behavior-tree' | 'bag' | 'folder';
|
|
3
4
|
export interface DirectoryListing {
|
|
4
5
|
dir: string;
|
|
5
6
|
parent: string | null;
|
|
6
7
|
entries: {
|
|
7
8
|
name: string;
|
|
8
|
-
kind: 'dir' |
|
|
9
|
+
kind: 'dir' | FileKind;
|
|
9
10
|
}[];
|
|
10
11
|
}
|
|
11
12
|
export declare function imageUrl(image: string): string | null;
|
|
@@ -17,6 +18,6 @@ export declare const api: {
|
|
|
17
18
|
deletePanel: (id: string) => Promise<void>;
|
|
18
19
|
listTopics: () => Promise<TopicInfo[]>;
|
|
19
20
|
listPlugins: () => Promise<PluginInfo[]>;
|
|
20
|
-
listFiles: (dir: string) => Promise<DirectoryListing>;
|
|
21
|
-
|
|
21
|
+
listFiles: (dir: string, kind?: FileKind) => Promise<DirectoryListing>;
|
|
22
|
+
uploadFile: (file: Blob) => Promise<string>;
|
|
22
23
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ArmSubscribe, type ArmUpdate, type ClientMessage, type CommandState, type GridSubscribe, type ImageSubscribe, type LogsSubscribe, type LogsUpdate, type PathSubscribe, type PathUpdate, type ServerMessage, type ServiceScope, type ServicesSubscribe, type ServicesUpdate, type ServiceVerb, type StreamStatus, type TfSubscribe, type TfUpdate, type TopicSubscribe } from '../shared/protocol.ts';
|
|
1
|
+
import { type ArmSubscribe, type ArmUpdate, type BehaviorTreeFile, type BehaviorTreeFileSubscribe, type BehaviorTreeInfo, type BehaviorTreeModels, type BehaviorTreePlaybackControl, type BehaviorTreePlaybackState, type BehaviorTreePlaybackSubscribe, type BehaviorTreeRecording, type BehaviorTreeSaved, type BehaviorTreeSubscribe, type BehaviorTreeUpdate, type ClientMessage, type CommandState, type GridSubscribe, type ImageSubscribe, type LogsSubscribe, type LogsUpdate, type PathSubscribe, type PathUpdate, type RosoutSubscribe, type RosoutUpdate, type ServerMessage, type ServiceScope, type ServicesSubscribe, type ServicesUpdate, type ServiceVerb, type StreamStatus, type TfSubscribe, type TfUpdate, type TopicSubscribe } from '../shared/protocol.ts';
|
|
2
2
|
export type ConnectionStatus = 'connecting' | 'open' | 'closed';
|
|
3
3
|
export type ImageOptions = Omit<ImageSubscribe, 'type' | 'id'>;
|
|
4
4
|
export type GridOptions = Omit<GridSubscribe, 'type' | 'id'>;
|
|
@@ -8,10 +8,30 @@ export type TopicOptions = Omit<TopicSubscribe, 'type' | 'id'>;
|
|
|
8
8
|
export type ServicesOptions = Omit<ServicesSubscribe, 'type' | 'id'>;
|
|
9
9
|
export type LogsOptions = Omit<LogsSubscribe, 'type' | 'id'>;
|
|
10
10
|
export type ArmOptions = Omit<ArmSubscribe, 'type' | 'id'>;
|
|
11
|
+
export type BehaviorTreeOptions = Omit<BehaviorTreeSubscribe, 'type' | 'id'>;
|
|
12
|
+
export type BehaviorTreePlaybackOptions = Omit<BehaviorTreePlaybackSubscribe, 'type' | 'id'>;
|
|
13
|
+
export type BehaviorTreePlaybackRequest = Omit<BehaviorTreePlaybackControl, 'type' | 'id'>;
|
|
14
|
+
export type BehaviorTreeFileOptions = Omit<BehaviorTreeFileSubscribe, 'type' | 'id'>;
|
|
15
|
+
export type RosoutOptions = Omit<RosoutSubscribe, 'type' | 'id'>;
|
|
11
16
|
export interface TopicHandlers {
|
|
12
17
|
status: (state: StreamStatus['state'], message: string) => void;
|
|
13
18
|
message: (messageType: string, message: unknown) => void;
|
|
14
19
|
}
|
|
20
|
+
export interface BehaviorTreeHandlers {
|
|
21
|
+
status: (state: StreamStatus['state'], message: string) => void;
|
|
22
|
+
tree: (tree: BehaviorTreeInfo) => void;
|
|
23
|
+
update: (update: BehaviorTreeUpdate) => void;
|
|
24
|
+
recording?: (recording: BehaviorTreeRecording['recording']) => void;
|
|
25
|
+
playback?: (state: BehaviorTreePlaybackState) => void;
|
|
26
|
+
}
|
|
27
|
+
export interface BehaviorTreeFileHandlers {
|
|
28
|
+
file: (file: BehaviorTreeFile) => void;
|
|
29
|
+
models: (models: BehaviorTreeModels) => void;
|
|
30
|
+
}
|
|
31
|
+
export interface RosoutHandlers {
|
|
32
|
+
status: (state: StreamStatus['state'], message: string) => void;
|
|
33
|
+
update: (update: RosoutUpdate) => void;
|
|
34
|
+
}
|
|
15
35
|
export interface FrameInfo {
|
|
16
36
|
width: number;
|
|
17
37
|
height: number;
|
|
@@ -51,6 +71,16 @@ export declare class Connection {
|
|
|
51
71
|
subscribeTopic(options: TopicOptions, handlers: TopicHandlers): () => void;
|
|
52
72
|
subscribeServices(options: ServicesOptions, callback: (update: ServicesUpdate) => void): () => void;
|
|
53
73
|
subscribeLogs(options: LogsOptions, callback: (update: LogsUpdate) => void): () => void;
|
|
74
|
+
subscribeBehaviorTree(options: BehaviorTreeOptions, handlers: BehaviorTreeHandlers): () => void;
|
|
75
|
+
recordBehaviorTree(topic: string, path: string | null): Promise<string | null>;
|
|
76
|
+
subscribeBehaviorTreePlayback(options: BehaviorTreePlaybackOptions, handlers: BehaviorTreeHandlers): {
|
|
77
|
+
id: number;
|
|
78
|
+
unsubscribe: () => void;
|
|
79
|
+
};
|
|
80
|
+
controlBehaviorTreePlayback(id: number, request: BehaviorTreePlaybackRequest): boolean;
|
|
81
|
+
subscribeBehaviorTreeFile(options: BehaviorTreeFileOptions, handlers: BehaviorTreeFileHandlers): () => void;
|
|
82
|
+
saveBehaviorTreeFile(path: string, text: string, base: string | null, create?: boolean): Promise<BehaviorTreeSaved>;
|
|
83
|
+
subscribeRosout(options: RosoutOptions, handlers: RosoutHandlers): () => void;
|
|
54
84
|
serviceAction(unit: string, scope: ServiceScope, verb: ServiceVerb): Promise<string | null>;
|
|
55
85
|
publish(topic: string, messageType: string, message: unknown): boolean;
|
|
56
86
|
callService<T = unknown>(service: string, serviceType: string, request?: unknown, timeoutMs?: number): Promise<T>;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
-
export declare function Modal({ title, onClose, children, wide, }: {
|
|
2
|
+
export declare function Modal({ title, onClose, children, wide, resizable, }: {
|
|
3
3
|
title: string;
|
|
4
4
|
onClose: () => void;
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
wide?: boolean;
|
|
7
|
+
resizable?: boolean;
|
|
7
8
|
}): import("react").JSX.Element;
|
|
8
9
|
export interface ConfirmOptions {
|
|
9
10
|
title: string;
|
|
@@ -6,6 +6,9 @@ export declare const CloseIcon: (props: SVGProps<SVGSVGElement>) => import("reac
|
|
|
6
6
|
export declare const TrashIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
7
7
|
export declare const CopyIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
8
8
|
export declare const UndoIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
9
|
+
export declare const RedoIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
10
|
+
export declare const SaveIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
11
|
+
export declare const CodeIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
9
12
|
export declare const MoreIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
10
13
|
export declare const SlidersIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
11
14
|
export declare const PencilIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
@@ -32,3 +35,24 @@ export declare const ArmIcon: (props: SVGProps<SVGSVGElement>) => import("react"
|
|
|
32
35
|
export declare const AngleIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
33
36
|
export declare const CubeIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
34
37
|
export declare const QuestionIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
38
|
+
export declare const TreeIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
39
|
+
export declare const TreeEditIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
40
|
+
export declare const ListIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
41
|
+
export declare const HistoryIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
42
|
+
export declare const ArrowRightIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
43
|
+
export declare const QuestionMarkIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
44
|
+
export declare const ParallelIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
45
|
+
export declare const ForkIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
46
|
+
export declare const DiamondIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
47
|
+
export declare const BoltIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
48
|
+
export declare const CheckCircleIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
49
|
+
export declare const RecordIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
50
|
+
export declare const PauseIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
51
|
+
export declare const FilmIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
52
|
+
export declare const LogsIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
53
|
+
export declare const NodesIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
54
|
+
export declare const SearchIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
55
|
+
export declare const BanIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
56
|
+
export declare const FilterIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
57
|
+
export declare const DownloadIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
58
|
+
export declare const ArrowDownToLineIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { defineWidget, definePlugin, type WidgetDefinition, type WidgetProps, type PropertySchema, type Property, type RegisteredWidget, type TasselloClientPlugin, } from '../widgets/types.ts';
|
|
2
|
-
export { connection, useConnectionStatus, useTopic, useTf, useCommandState, type Connection, type ConnectionStatus, type TopicState, type TopicHandlers, type TopicOptions, type PluginStreamHandlers, type StreamHandlers, type FrameInfo, type ImageOptions, type TfOptions, } from '../connection.ts';
|
|
2
|
+
export { connection, useConnectionStatus, useTopic, useTf, useCommandState, type BehaviorTreeFileHandlers, type BehaviorTreeFileOptions, type BehaviorTreeHandlers, type BehaviorTreeOptions, type BehaviorTreePlaybackOptions, type BehaviorTreePlaybackRequest, type Connection, type ConnectionStatus, type TopicState, type TopicHandlers, type TopicOptions, type PluginStreamHandlers, type RosoutHandlers, type RosoutOptions, type StreamHandlers, type FrameInfo, type ImageOptions, type TfOptions, } from '../connection.ts';
|
|
3
3
|
export { imageUrl } from '../api.ts';
|
|
4
4
|
export { useDialogs, Modal, type Dialogs, type ConfirmOptions, type PromptOptions } from '../dialogs.tsx';
|
|
5
5
|
export { notify } from '../notifications.tsx';
|
|
6
6
|
export { Joystick, type JoystickProps } from '../widgets/Joystick.tsx';
|
|
7
7
|
export * from '../icons.tsx';
|
|
8
|
-
export type { CommandState, ClientMessage, ServerMessage, StreamStatus, TfUpdate, Transform2D } from '../../shared/protocol.ts';
|
|
8
|
+
export type { BehaviorTreeFile, BehaviorTreeInfo, BehaviorTreeModels, BehaviorTreePlaybackState, BehaviorTreeRecording, BehaviorTreeSaved, BehaviorTreeUpdate, BtNode, BtNodeLibrary, BtNodeState, BtTransition, CommandState, ClientMessage, LogEntry, RosoutUpdate, ServerMessage, StreamStatus, TfUpdate, Transform2D, } from '../../shared/protocol.ts';
|
|
9
|
+
export type { BtNodeModel, BtPortModel } from '../../shared/bt_nodes.ts';
|
|
9
10
|
export type { Panel, WidgetInstance } from '../../shared/panel.ts';
|
|
@@ -40,6 +40,10 @@ type PropertyKind<V> = [V] extends [boolean] ? {
|
|
|
40
40
|
kind: 'image';
|
|
41
41
|
default: V;
|
|
42
42
|
placeholder?: string;
|
|
43
|
+
} | {
|
|
44
|
+
kind: 'behavior-tree';
|
|
45
|
+
default: V;
|
|
46
|
+
placeholder?: string;
|
|
43
47
|
} : never;
|
|
44
48
|
export type PropertySchema<C> = {
|
|
45
49
|
[K in keyof C & string]: PropertyBase<C, K> & PropertyKind<C[K]>;
|
|
@@ -83,7 +87,7 @@ export type Property = PropertyBase<Config, string> & (PropertyKind<boolean> | P
|
|
|
83
87
|
label: string;
|
|
84
88
|
}[];
|
|
85
89
|
} | {
|
|
86
|
-
kind: 'image';
|
|
90
|
+
kind: 'image' | 'behavior-tree';
|
|
87
91
|
default: string;
|
|
88
92
|
placeholder?: string;
|
|
89
93
|
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { BtNodeKind } from './protocol.ts';
|
|
2
|
+
export interface BtPortModel {
|
|
3
|
+
name: string;
|
|
4
|
+
direction: 'input' | 'output' | 'inout';
|
|
5
|
+
type: string;
|
|
6
|
+
default: string | null;
|
|
7
|
+
description: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BtNodeModel {
|
|
10
|
+
id: string;
|
|
11
|
+
kind: BtNodeKind;
|
|
12
|
+
ports: BtPortModel[];
|
|
13
|
+
description: string;
|
|
14
|
+
}
|
|
15
|
+
export declare const EXPLICIT: Record<string, BtNodeKind>;
|
|
16
|
+
export interface ModelElement {
|
|
17
|
+
name: string;
|
|
18
|
+
attributes: Record<string, string>;
|
|
19
|
+
children: ModelElement[];
|
|
20
|
+
text: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function readModels(root: ModelElement): BtNodeModel[];
|
|
23
|
+
export declare function builtinModels(format: 3 | 4): BtNodeModel[];
|
|
24
|
+
export declare const KNOWN_KINDS: Map<string, BtNodeKind>;
|
|
25
|
+
export declare function guessKind(type: string, children: number): BtNodeKind;
|