tassello 0.2.0 → 0.3.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 +38 -0
- package/README.md +112 -8
- package/dist/server/behavior_tree_files.d.ts +0 -1
- package/dist/server/behavior_tree_files.js +2 -25
- package/dist/server/diagnostics.d.ts +16 -0
- package/dist/server/diagnostics.js +200 -0
- package/dist/server/diagnostics_state.d.ts +23 -0
- package/dist/server/diagnostics_state.js +146 -0
- package/dist/server/disks.d.ts +14 -0
- package/dist/server/disks.js +152 -0
- package/dist/server/file_manager.d.ts +25 -0
- package/dist/server/file_manager.js +717 -0
- package/dist/server/http.js +248 -5
- package/dist/server/netpbm.d.ts +3 -0
- package/dist/server/netpbm.js +69 -0
- package/dist/server/pty.d.ts +26 -0
- package/dist/server/pty.js +150 -0
- package/dist/server/server.js +9 -2
- package/dist/server/session.d.ts +7 -1
- package/dist/server/session.js +67 -1
- package/dist/server/terminal_output.d.ts +25 -0
- package/dist/server/terminal_output.js +108 -0
- package/dist/server/terminals.d.ts +32 -0
- package/dist/server/terminals.js +366 -0
- package/dist/server/util.d.ts +4 -0
- package/dist/server/util.js +45 -1
- package/dist/shared/file_manager.d.ts +130 -0
- package/dist/shared/file_manager.js +7 -0
- package/dist/shared/protocol.d.ts +87 -2
- package/dist/shared/protocol.js +8 -0
- package/dist/types/client/api.d.ts +22 -0
- package/dist/types/client/connection.d.ts +22 -1
- package/dist/types/client/icons.d.ts +27 -0
- package/dist/types/client/sdk/index.d.ts +4 -3
- package/dist/types/shared/file_manager.d.ts +130 -0
- package/dist/types/shared/protocol.d.ts +87 -2
- package/dist/www/assets/Joystick.js +1 -1
- package/dist/www/assets/RobotModelView.js +2 -2
- package/dist/www/assets/TerminalView.css +1 -0
- package/dist/www/assets/TerminalView.js +17 -0
- package/dist/www/assets/dialogs.js +1 -0
- package/dist/www/assets/icons.js +1 -1
- package/dist/www/assets/index.css +1 -1
- package/dist/www/assets/index.js +59 -19
- package/dist/www/assets/keys.js +3 -0
- package/dist/www/assets/shared/tassello-sdk.js +1 -1
- package/dist/www/index.html +2 -0
- package/docs/plugins.md +20 -0
- package/package.json +6 -2
package/dist/server/util.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { existsSync, promises as fs } from 'node:fs';
|
|
2
3
|
import os from 'node:os';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
// The share directory of a ROS package, from the ament index of the sourced
|
|
@@ -26,6 +27,27 @@ export function absoluteTopic(topic) {
|
|
|
26
27
|
const trimmed = topic.trim().replace(/\/+$/, '');
|
|
27
28
|
return trimmed.startsWith('/') ? trimmed : `/${trimmed}`;
|
|
28
29
|
}
|
|
30
|
+
// Whether the page that opened a WebSocket is one of the dashboard's own.
|
|
31
|
+
// Browsers say which site a page is from (Origin), and another site's page
|
|
32
|
+
// cannot change it; the dashboard's is the host the page reached: the Host
|
|
33
|
+
// header, or the X-Forwarded-Host of a reverse proxy. Programs other than
|
|
34
|
+
// browsers send no Origin.
|
|
35
|
+
export function ownPage(headers) {
|
|
36
|
+
if (headers.origin === undefined) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
let host;
|
|
40
|
+
try {
|
|
41
|
+
host = new URL(headers.origin).host.toLowerCase();
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
// "null": a sandboxed frame, a file
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const forwarded = headers['x-forwarded-host'];
|
|
48
|
+
const proxied = (Array.isArray(forwarded) ? forwarded[0] : forwarded)?.split(',')[0].trim();
|
|
49
|
+
return [headers.host, proxied].some((reached) => reached?.toLowerCase() === host);
|
|
50
|
+
}
|
|
29
51
|
export function errorMessage(e) {
|
|
30
52
|
return e instanceof Error ? e.message : String(e);
|
|
31
53
|
}
|
|
@@ -52,3 +74,25 @@ export function toJson(value) {
|
|
|
52
74
|
}
|
|
53
75
|
return value;
|
|
54
76
|
}
|
|
77
|
+
// Of a file's content
|
|
78
|
+
export function contentVersion(text) {
|
|
79
|
+
return createHash('sha256').update(text).digest('hex').slice(0, 16);
|
|
80
|
+
}
|
|
81
|
+
// Writes the file anew, at once: a temporary file renamed over it, keeping
|
|
82
|
+
// its mode; in place if that cannot be (a folder the server cannot write in,
|
|
83
|
+
// a file of another user's)
|
|
84
|
+
export async function replaceFile(file, text) {
|
|
85
|
+
const stat = await fs.stat(file);
|
|
86
|
+
if (stat.uid === process.getuid?.()) {
|
|
87
|
+
const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${randomBytes(4).toString('hex')}.tmp`);
|
|
88
|
+
try {
|
|
89
|
+
await fs.writeFile(temporary, text, { mode: stat.mode & 0o7777, flag: 'wx' });
|
|
90
|
+
await fs.rename(temporary, file);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
await fs.rm(temporary, { force: true });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
await fs.writeFile(file, text);
|
|
98
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export interface FsEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
kind: 'dir' | 'file' | 'other';
|
|
4
|
+
link: string | null;
|
|
5
|
+
size: number;
|
|
6
|
+
modified: number;
|
|
7
|
+
mode: number;
|
|
8
|
+
owner: string;
|
|
9
|
+
group: string;
|
|
10
|
+
readable: boolean;
|
|
11
|
+
writable: boolean;
|
|
12
|
+
bag: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface FsSpace {
|
|
15
|
+
mount: string;
|
|
16
|
+
total: number;
|
|
17
|
+
free: number;
|
|
18
|
+
}
|
|
19
|
+
export interface FsListing {
|
|
20
|
+
path: string;
|
|
21
|
+
parent: string | null;
|
|
22
|
+
entries: FsEntry[];
|
|
23
|
+
truncated: number;
|
|
24
|
+
writable: boolean;
|
|
25
|
+
version: string;
|
|
26
|
+
space: FsSpace | null;
|
|
27
|
+
}
|
|
28
|
+
export interface FsPlaces {
|
|
29
|
+
home: string;
|
|
30
|
+
user: string;
|
|
31
|
+
ros: {
|
|
32
|
+
name: string;
|
|
33
|
+
path: string;
|
|
34
|
+
}[];
|
|
35
|
+
}
|
|
36
|
+
export interface FsDetails extends FsEntry {
|
|
37
|
+
path: string;
|
|
38
|
+
realPath: string | null;
|
|
39
|
+
created: number | null;
|
|
40
|
+
accessed: number;
|
|
41
|
+
changed: number;
|
|
42
|
+
inode: number;
|
|
43
|
+
links: number;
|
|
44
|
+
items: number | null;
|
|
45
|
+
hidden: number | null;
|
|
46
|
+
space: FsSpace | null;
|
|
47
|
+
}
|
|
48
|
+
export interface FsDisk extends FsSpace {
|
|
49
|
+
device: string;
|
|
50
|
+
type: string;
|
|
51
|
+
readOnly: boolean;
|
|
52
|
+
used: number;
|
|
53
|
+
inodes: {
|
|
54
|
+
total: number;
|
|
55
|
+
free: number;
|
|
56
|
+
} | null;
|
|
57
|
+
}
|
|
58
|
+
export interface FsAnalysis {
|
|
59
|
+
path: string;
|
|
60
|
+
size: number;
|
|
61
|
+
disk: number;
|
|
62
|
+
files: number;
|
|
63
|
+
folders: number;
|
|
64
|
+
links: number;
|
|
65
|
+
children: {
|
|
66
|
+
name: string;
|
|
67
|
+
kind: FsEntry['kind'];
|
|
68
|
+
size: number;
|
|
69
|
+
files: number;
|
|
70
|
+
}[];
|
|
71
|
+
types: {
|
|
72
|
+
type: string;
|
|
73
|
+
files: number;
|
|
74
|
+
size: number;
|
|
75
|
+
}[];
|
|
76
|
+
largest: {
|
|
77
|
+
path: string;
|
|
78
|
+
size: number;
|
|
79
|
+
}[];
|
|
80
|
+
recent: {
|
|
81
|
+
path: string;
|
|
82
|
+
modified: number;
|
|
83
|
+
}[];
|
|
84
|
+
partial: string | null;
|
|
85
|
+
unreadable: number;
|
|
86
|
+
mounts: number;
|
|
87
|
+
elapsedMs: number;
|
|
88
|
+
}
|
|
89
|
+
export interface FsText {
|
|
90
|
+
path: string;
|
|
91
|
+
text: string;
|
|
92
|
+
version: string;
|
|
93
|
+
stamp: string;
|
|
94
|
+
readOnly: string | null;
|
|
95
|
+
}
|
|
96
|
+
export interface FsSaved {
|
|
97
|
+
version: string;
|
|
98
|
+
stamp: string;
|
|
99
|
+
conflict: boolean;
|
|
100
|
+
}
|
|
101
|
+
export type FsConflict = 'ask' | 'skip' | 'keep-both' | 'replace';
|
|
102
|
+
export type FsOperation = {
|
|
103
|
+
op: 'mkdir';
|
|
104
|
+
path: string;
|
|
105
|
+
} | {
|
|
106
|
+
op: 'create';
|
|
107
|
+
path: string;
|
|
108
|
+
} | {
|
|
109
|
+
op: 'rename';
|
|
110
|
+
path: string;
|
|
111
|
+
name: string;
|
|
112
|
+
} | {
|
|
113
|
+
op: 'move' | 'copy';
|
|
114
|
+
paths: string[];
|
|
115
|
+
to: string;
|
|
116
|
+
conflict: FsConflict;
|
|
117
|
+
} | {
|
|
118
|
+
op: 'delete';
|
|
119
|
+
paths: string[];
|
|
120
|
+
} | {
|
|
121
|
+
op: 'chmod';
|
|
122
|
+
path: string;
|
|
123
|
+
mode: number;
|
|
124
|
+
};
|
|
125
|
+
export interface FsResult {
|
|
126
|
+
paths: string[];
|
|
127
|
+
conflicts: string[];
|
|
128
|
+
}
|
|
129
|
+
export declare const FS_MAX_ENTRIES = 5000;
|
|
130
|
+
export declare const FS_MAX_TEXT_BYTES: number;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// The robot's files, as the file manager widgets see them: the REST API of
|
|
2
|
+
// /api/fs (see src/server/http.ts). The server acts as its user, anywhere that
|
|
3
|
+
// user can: see the README's Security.
|
|
4
|
+
// Of a folder's entries, at most, listed
|
|
5
|
+
export const FS_MAX_ENTRIES = 5000;
|
|
6
|
+
// Of the files edited as text
|
|
7
|
+
export const FS_MAX_TEXT_BYTES = 5 * 1024 * 1024;
|
|
@@ -192,7 +192,44 @@ export interface RosoutSubscribe {
|
|
|
192
192
|
id: number;
|
|
193
193
|
topic: string;
|
|
194
194
|
}
|
|
195
|
-
export
|
|
195
|
+
export interface DiagnosticsSubscribe {
|
|
196
|
+
type: 'diagnostics.subscribe';
|
|
197
|
+
id: number;
|
|
198
|
+
topic: string;
|
|
199
|
+
}
|
|
200
|
+
export interface TerminalOpen {
|
|
201
|
+
type: 'terminal.open';
|
|
202
|
+
id: number;
|
|
203
|
+
terminal: string;
|
|
204
|
+
command: string;
|
|
205
|
+
folder: string;
|
|
206
|
+
cols: number;
|
|
207
|
+
rows: number;
|
|
208
|
+
started: number | null;
|
|
209
|
+
offset: number | null;
|
|
210
|
+
}
|
|
211
|
+
export interface TerminalInput {
|
|
212
|
+
type: 'terminal.input';
|
|
213
|
+
id: number;
|
|
214
|
+
data: string;
|
|
215
|
+
}
|
|
216
|
+
export interface TerminalResize {
|
|
217
|
+
type: 'terminal.resize';
|
|
218
|
+
id: number;
|
|
219
|
+
cols: number;
|
|
220
|
+
rows: number;
|
|
221
|
+
}
|
|
222
|
+
export interface TerminalAck {
|
|
223
|
+
type: 'terminal.ack';
|
|
224
|
+
id: number;
|
|
225
|
+
started: number;
|
|
226
|
+
offset: number;
|
|
227
|
+
}
|
|
228
|
+
export interface TerminalRestart {
|
|
229
|
+
type: 'terminal.restart';
|
|
230
|
+
id: number;
|
|
231
|
+
}
|
|
232
|
+
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 | DiagnosticsSubscribe | TerminalOpen | TerminalInput | TerminalResize | TerminalAck | TerminalRestart;
|
|
196
233
|
export interface Hello {
|
|
197
234
|
type: 'hello';
|
|
198
235
|
clientId: string;
|
|
@@ -429,7 +466,51 @@ export interface RosoutUpdate {
|
|
|
429
466
|
skipped: number;
|
|
430
467
|
nodes: string[] | null;
|
|
431
468
|
}
|
|
432
|
-
export
|
|
469
|
+
export interface DiagnosticEntry {
|
|
470
|
+
id: number;
|
|
471
|
+
name: string;
|
|
472
|
+
level: number;
|
|
473
|
+
message: string;
|
|
474
|
+
hardwareId: string;
|
|
475
|
+
values: {
|
|
476
|
+
key: string;
|
|
477
|
+
value: string;
|
|
478
|
+
}[];
|
|
479
|
+
stale: boolean;
|
|
480
|
+
updated: number;
|
|
481
|
+
since: number;
|
|
482
|
+
}
|
|
483
|
+
export interface DiagnosticChange {
|
|
484
|
+
seq: number;
|
|
485
|
+
time: number;
|
|
486
|
+
status: number;
|
|
487
|
+
level: number;
|
|
488
|
+
message: string;
|
|
489
|
+
}
|
|
490
|
+
export interface DiagnosticsUpdate {
|
|
491
|
+
type: 'diagnostics';
|
|
492
|
+
id: number;
|
|
493
|
+
reset: boolean;
|
|
494
|
+
started: number;
|
|
495
|
+
statuses: DiagnosticEntry[];
|
|
496
|
+
changes: DiagnosticChange[];
|
|
497
|
+
}
|
|
498
|
+
export interface TerminalOutput {
|
|
499
|
+
type: 'terminal.output';
|
|
500
|
+
id: number;
|
|
501
|
+
started: number;
|
|
502
|
+
offset: number;
|
|
503
|
+
reset: boolean;
|
|
504
|
+
data: string;
|
|
505
|
+
title: string | null;
|
|
506
|
+
}
|
|
507
|
+
export interface TerminalExit {
|
|
508
|
+
type: 'terminal.exit';
|
|
509
|
+
id: number;
|
|
510
|
+
started: number;
|
|
511
|
+
exitCode: number | null;
|
|
512
|
+
}
|
|
513
|
+
export type ServerMessage = Hello | CommandStates | CommandUpdate | StreamStatus | TfUpdate | PathUpdate | TopicMessage | ServicesUpdate | ServiceResult | LogsUpdate | ArmUpdate | Result | PluginData | BehaviorTreeInfo | BehaviorTreeUpdate | BehaviorTreeRecording | BehaviorTreePlaybackState | BehaviorTreeFile | BehaviorTreeModels | RosoutUpdate | DiagnosticsUpdate | TerminalOutput | TerminalExit | PanelsChanged | ErrorMessage;
|
|
433
514
|
export declare const FRAME_HEADER_BYTES = 11;
|
|
434
515
|
export declare const IMAGE_FORMATS: readonly ['image/jpeg', 'image/png'];
|
|
435
516
|
export interface GridInfo {
|
|
@@ -452,6 +533,10 @@ export declare const ARM_STATE_RATE = 10;
|
|
|
452
533
|
export declare const BT_RATE = 10;
|
|
453
534
|
export declare const ROSOUT_RATE = 10;
|
|
454
535
|
export declare const ROSOUT_HISTORY = 10000;
|
|
536
|
+
export declare const DIAGNOSTICS_RATE = 4;
|
|
537
|
+
export declare const DIAGNOSTICS_CHANGES = 1000;
|
|
538
|
+
export declare const TERMINAL_SCROLLBACK = 2000;
|
|
539
|
+
export declare const TERMINAL_WINDOW: number;
|
|
455
540
|
export declare const DASHBOARD_CLIENT_HEADER = "X-Dashboard-Client";
|
|
456
541
|
export interface PluginInfo {
|
|
457
542
|
name: string;
|
package/dist/shared/protocol.js
CHANGED
|
@@ -19,4 +19,12 @@ export const BT_RATE = 10;
|
|
|
19
19
|
export const ROSOUT_RATE = 10;
|
|
20
20
|
// Messages of the ROS log kept by the server, and by the page
|
|
21
21
|
export const ROSOUT_HISTORY = 10_000;
|
|
22
|
+
// Diagnostics come about once a second
|
|
23
|
+
export const DIAGNOSTICS_RATE = 4;
|
|
24
|
+
// Changes of level kept by the server, and by the page
|
|
25
|
+
export const DIAGNOSTICS_CHANGES = 1000;
|
|
26
|
+
// Lines of a terminal kept above its screen, by the server and by the page
|
|
27
|
+
export const TERMINAL_SCROLLBACK = 2000;
|
|
28
|
+
// Characters of a terminal's output sent to a page and not yet written by it
|
|
29
|
+
export const TERMINAL_WINDOW = 256 * 1024;
|
|
22
30
|
export const DASHBOARD_CLIENT_HEADER = 'X-Dashboard-Client';
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
import type { FsAnalysis, FsConflict, FsDetails, FsDisk, FsListing, FsOperation, FsPlaces, FsResult, FsSaved, FsText } from '../shared/file_manager.ts';
|
|
1
2
|
import type { Panel, PanelSummary, TopicInfo } from '../shared/panel.ts';
|
|
2
3
|
import { type PluginInfo } from '../shared/protocol.ts';
|
|
4
|
+
export declare class ApiError extends Error {
|
|
5
|
+
readonly status: number;
|
|
6
|
+
constructor(status: number, message: string);
|
|
7
|
+
}
|
|
3
8
|
export type FileKind = 'image' | 'behavior-tree' | 'bag' | 'folder';
|
|
4
9
|
export interface DirectoryListing {
|
|
5
10
|
dir: string;
|
|
@@ -21,3 +26,20 @@ export declare const api: {
|
|
|
21
26
|
listFiles: (dir: string, kind?: FileKind) => Promise<DirectoryListing>;
|
|
22
27
|
uploadFile: (file: Blob) => Promise<string>;
|
|
23
28
|
};
|
|
29
|
+
export interface Upload {
|
|
30
|
+
result: Promise<FsResult>;
|
|
31
|
+
abort: () => void;
|
|
32
|
+
}
|
|
33
|
+
export declare const fsApi: {
|
|
34
|
+
places: () => Promise<FsPlaces>;
|
|
35
|
+
list: (path: string, known?: string) => Promise<FsListing | undefined>;
|
|
36
|
+
details: (path: string) => Promise<FsDetails>;
|
|
37
|
+
disks: () => Promise<FsDisk[]>;
|
|
38
|
+
analyze: (path: string) => Promise<FsAnalysis>;
|
|
39
|
+
readText: (path: string, stamp?: string) => Promise<FsText | undefined>;
|
|
40
|
+
saveText: (path: string, text: string, base: string | null, create?: boolean) => Promise<FsSaved>;
|
|
41
|
+
operate: (operation: FsOperation) => Promise<FsResult>;
|
|
42
|
+
downloadUrl: (paths: string[]) => string;
|
|
43
|
+
viewUrl: (path: string, stamp?: string) => string;
|
|
44
|
+
upload(folder: string, name: string, file: Blob, conflict: FsConflict, onProgress: (sent: number) => void): Upload;
|
|
45
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
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';
|
|
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 DiagnosticsSubscribe, type DiagnosticsUpdate, 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 TerminalExit, type TerminalOpen, type TerminalOutput, 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'>;
|
|
@@ -13,6 +13,8 @@ export type BehaviorTreePlaybackOptions = Omit<BehaviorTreePlaybackSubscribe, 't
|
|
|
13
13
|
export type BehaviorTreePlaybackRequest = Omit<BehaviorTreePlaybackControl, 'type' | 'id'>;
|
|
14
14
|
export type BehaviorTreeFileOptions = Omit<BehaviorTreeFileSubscribe, 'type' | 'id'>;
|
|
15
15
|
export type RosoutOptions = Omit<RosoutSubscribe, 'type' | 'id'>;
|
|
16
|
+
export type DiagnosticsOptions = Omit<DiagnosticsSubscribe, 'type' | 'id'>;
|
|
17
|
+
export type TerminalOptions = Pick<TerminalOpen, 'terminal' | 'command' | 'folder'>;
|
|
16
18
|
export interface TopicHandlers {
|
|
17
19
|
status: (state: StreamStatus['state'], message: string) => void;
|
|
18
20
|
message: (messageType: string, message: unknown) => void;
|
|
@@ -32,6 +34,16 @@ export interface RosoutHandlers {
|
|
|
32
34
|
status: (state: StreamStatus['state'], message: string) => void;
|
|
33
35
|
update: (update: RosoutUpdate) => void;
|
|
34
36
|
}
|
|
37
|
+
export interface DiagnosticsHandlers {
|
|
38
|
+
status: (state: StreamStatus['state'], message: string) => void;
|
|
39
|
+
update: (update: DiagnosticsUpdate) => void;
|
|
40
|
+
}
|
|
41
|
+
export interface TerminalHandlers {
|
|
42
|
+
status: (state: StreamStatus['state'], message: string) => void;
|
|
43
|
+
output: (output: TerminalOutput) => void;
|
|
44
|
+
exit: (exit: TerminalExit) => void;
|
|
45
|
+
shown: () => Pick<TerminalOpen, 'cols' | 'rows' | 'started' | 'offset'>;
|
|
46
|
+
}
|
|
35
47
|
export interface FrameInfo {
|
|
36
48
|
width: number;
|
|
37
49
|
height: number;
|
|
@@ -81,6 +93,15 @@ export declare class Connection {
|
|
|
81
93
|
subscribeBehaviorTreeFile(options: BehaviorTreeFileOptions, handlers: BehaviorTreeFileHandlers): () => void;
|
|
82
94
|
saveBehaviorTreeFile(path: string, text: string, base: string | null, create?: boolean): Promise<BehaviorTreeSaved>;
|
|
83
95
|
subscribeRosout(options: RosoutOptions, handlers: RosoutHandlers): () => void;
|
|
96
|
+
subscribeDiagnostics(options: DiagnosticsOptions, handlers: DiagnosticsHandlers): () => void;
|
|
97
|
+
subscribeTerminal(options: TerminalOptions, handlers: TerminalHandlers): {
|
|
98
|
+
id: number;
|
|
99
|
+
unsubscribe: () => void;
|
|
100
|
+
};
|
|
101
|
+
terminalInput(id: number, data: string): boolean;
|
|
102
|
+
resizeTerminal(id: number, cols: number, rows: number): boolean;
|
|
103
|
+
ackTerminal(id: number, started: number, offset: number): boolean;
|
|
104
|
+
restartTerminal(id: number): boolean;
|
|
84
105
|
serviceAction(unit: string, scope: ServiceScope, verb: ServiceVerb): Promise<string | null>;
|
|
85
106
|
publish(topic: string, messageType: string, message: unknown): boolean;
|
|
86
107
|
callService<T = unknown>(service: string, serviceType: string, request?: unknown, timeoutMs?: number): Promise<T>;
|
|
@@ -56,3 +56,30 @@ export declare const BanIcon: (props: SVGProps<SVGSVGElement>) => import("react"
|
|
|
56
56
|
export declare const FilterIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
57
57
|
export declare const DownloadIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
58
58
|
export declare const ArrowDownToLineIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
59
|
+
export declare const DiagnosticsIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
60
|
+
export declare const UnfoldIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
61
|
+
export declare const FolderIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
62
|
+
export declare const FolderPlusIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
63
|
+
export declare const FileIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
64
|
+
export declare const FileTextIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
65
|
+
export declare const FilePlusIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
66
|
+
export declare const UploadIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
67
|
+
export declare const ArrowUpIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
68
|
+
export declare const ArrowLeftIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
69
|
+
export declare const HomeIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
70
|
+
export declare const HardDriveIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
71
|
+
export declare const BookmarkIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
72
|
+
export declare const SidebarIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
73
|
+
export declare const PieChartIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
74
|
+
export declare const InfoIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
75
|
+
export declare const WrapIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
76
|
+
export declare const LinkIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
77
|
+
export declare const LockIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
78
|
+
export declare const ArchiveIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
79
|
+
export declare const ShellIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
80
|
+
export declare const KeyboardIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
81
|
+
export declare const MaximizeIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
82
|
+
export declare const MinimizeIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
83
|
+
export declare const ClipboardIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
84
|
+
export declare const TextSmallerIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
85
|
+
export declare const TextLargerIcon: (props: SVGProps<SVGSVGElement>) => import("react").JSX.Element;
|
|
@@ -1,10 +1,11 @@
|
|
|
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 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
|
-
export { imageUrl } from '../api.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 DiagnosticsHandlers, type DiagnosticsOptions, type TerminalHandlers, type TerminalOptions, type StreamHandlers, type FrameInfo, type ImageOptions, type TfOptions, } from '../connection.ts';
|
|
3
|
+
export { imageUrl, fsApi, ApiError, type Upload } 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 { BehaviorTreeFile, BehaviorTreeInfo, BehaviorTreeModels, BehaviorTreePlaybackState, BehaviorTreeRecording, BehaviorTreeSaved, BehaviorTreeUpdate, BtNode, BtNodeLibrary, BtNodeState, BtTransition, CommandState, ClientMessage, LogEntry, RosoutUpdate, ServerMessage, StreamStatus, TfUpdate, Transform2D, } from '../../shared/protocol.ts';
|
|
8
|
+
export type { BehaviorTreeFile, BehaviorTreeInfo, BehaviorTreeModels, BehaviorTreePlaybackState, BehaviorTreeRecording, BehaviorTreeSaved, BehaviorTreeUpdate, BtNode, BtNodeLibrary, BtNodeState, BtTransition, CommandState, ClientMessage, DiagnosticChange, DiagnosticEntry, DiagnosticsUpdate, LogEntry, RosoutUpdate, ServerMessage, StreamStatus, TerminalExit, TerminalOutput, TfUpdate, Transform2D, } from '../../shared/protocol.ts';
|
|
9
9
|
export type { BtNodeModel, BtPortModel } from '../../shared/bt_nodes.ts';
|
|
10
|
+
export type { FsAnalysis, FsConflict, FsDetails, FsDisk, FsEntry, FsListing, FsOperation, FsPlaces, FsResult, FsSaved, FsSpace, FsText, } from '../../shared/file_manager.ts';
|
|
10
11
|
export type { Panel, WidgetInstance } from '../../shared/panel.ts';
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export interface FsEntry {
|
|
2
|
+
name: string;
|
|
3
|
+
kind: 'dir' | 'file' | 'other';
|
|
4
|
+
link: string | null;
|
|
5
|
+
size: number;
|
|
6
|
+
modified: number;
|
|
7
|
+
mode: number;
|
|
8
|
+
owner: string;
|
|
9
|
+
group: string;
|
|
10
|
+
readable: boolean;
|
|
11
|
+
writable: boolean;
|
|
12
|
+
bag: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface FsSpace {
|
|
15
|
+
mount: string;
|
|
16
|
+
total: number;
|
|
17
|
+
free: number;
|
|
18
|
+
}
|
|
19
|
+
export interface FsListing {
|
|
20
|
+
path: string;
|
|
21
|
+
parent: string | null;
|
|
22
|
+
entries: FsEntry[];
|
|
23
|
+
truncated: number;
|
|
24
|
+
writable: boolean;
|
|
25
|
+
version: string;
|
|
26
|
+
space: FsSpace | null;
|
|
27
|
+
}
|
|
28
|
+
export interface FsPlaces {
|
|
29
|
+
home: string;
|
|
30
|
+
user: string;
|
|
31
|
+
ros: {
|
|
32
|
+
name: string;
|
|
33
|
+
path: string;
|
|
34
|
+
}[];
|
|
35
|
+
}
|
|
36
|
+
export interface FsDetails extends FsEntry {
|
|
37
|
+
path: string;
|
|
38
|
+
realPath: string | null;
|
|
39
|
+
created: number | null;
|
|
40
|
+
accessed: number;
|
|
41
|
+
changed: number;
|
|
42
|
+
inode: number;
|
|
43
|
+
links: number;
|
|
44
|
+
items: number | null;
|
|
45
|
+
hidden: number | null;
|
|
46
|
+
space: FsSpace | null;
|
|
47
|
+
}
|
|
48
|
+
export interface FsDisk extends FsSpace {
|
|
49
|
+
device: string;
|
|
50
|
+
type: string;
|
|
51
|
+
readOnly: boolean;
|
|
52
|
+
used: number;
|
|
53
|
+
inodes: {
|
|
54
|
+
total: number;
|
|
55
|
+
free: number;
|
|
56
|
+
} | null;
|
|
57
|
+
}
|
|
58
|
+
export interface FsAnalysis {
|
|
59
|
+
path: string;
|
|
60
|
+
size: number;
|
|
61
|
+
disk: number;
|
|
62
|
+
files: number;
|
|
63
|
+
folders: number;
|
|
64
|
+
links: number;
|
|
65
|
+
children: {
|
|
66
|
+
name: string;
|
|
67
|
+
kind: FsEntry['kind'];
|
|
68
|
+
size: number;
|
|
69
|
+
files: number;
|
|
70
|
+
}[];
|
|
71
|
+
types: {
|
|
72
|
+
type: string;
|
|
73
|
+
files: number;
|
|
74
|
+
size: number;
|
|
75
|
+
}[];
|
|
76
|
+
largest: {
|
|
77
|
+
path: string;
|
|
78
|
+
size: number;
|
|
79
|
+
}[];
|
|
80
|
+
recent: {
|
|
81
|
+
path: string;
|
|
82
|
+
modified: number;
|
|
83
|
+
}[];
|
|
84
|
+
partial: string | null;
|
|
85
|
+
unreadable: number;
|
|
86
|
+
mounts: number;
|
|
87
|
+
elapsedMs: number;
|
|
88
|
+
}
|
|
89
|
+
export interface FsText {
|
|
90
|
+
path: string;
|
|
91
|
+
text: string;
|
|
92
|
+
version: string;
|
|
93
|
+
stamp: string;
|
|
94
|
+
readOnly: string | null;
|
|
95
|
+
}
|
|
96
|
+
export interface FsSaved {
|
|
97
|
+
version: string;
|
|
98
|
+
stamp: string;
|
|
99
|
+
conflict: boolean;
|
|
100
|
+
}
|
|
101
|
+
export type FsConflict = 'ask' | 'skip' | 'keep-both' | 'replace';
|
|
102
|
+
export type FsOperation = {
|
|
103
|
+
op: 'mkdir';
|
|
104
|
+
path: string;
|
|
105
|
+
} | {
|
|
106
|
+
op: 'create';
|
|
107
|
+
path: string;
|
|
108
|
+
} | {
|
|
109
|
+
op: 'rename';
|
|
110
|
+
path: string;
|
|
111
|
+
name: string;
|
|
112
|
+
} | {
|
|
113
|
+
op: 'move' | 'copy';
|
|
114
|
+
paths: string[];
|
|
115
|
+
to: string;
|
|
116
|
+
conflict: FsConflict;
|
|
117
|
+
} | {
|
|
118
|
+
op: 'delete';
|
|
119
|
+
paths: string[];
|
|
120
|
+
} | {
|
|
121
|
+
op: 'chmod';
|
|
122
|
+
path: string;
|
|
123
|
+
mode: number;
|
|
124
|
+
};
|
|
125
|
+
export interface FsResult {
|
|
126
|
+
paths: string[];
|
|
127
|
+
conflicts: string[];
|
|
128
|
+
}
|
|
129
|
+
export declare const FS_MAX_ENTRIES = 5000;
|
|
130
|
+
export declare const FS_MAX_TEXT_BYTES: number;
|