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.
Files changed (49) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +112 -8
  3. package/dist/server/behavior_tree_files.d.ts +0 -1
  4. package/dist/server/behavior_tree_files.js +2 -25
  5. package/dist/server/diagnostics.d.ts +16 -0
  6. package/dist/server/diagnostics.js +200 -0
  7. package/dist/server/diagnostics_state.d.ts +23 -0
  8. package/dist/server/diagnostics_state.js +146 -0
  9. package/dist/server/disks.d.ts +14 -0
  10. package/dist/server/disks.js +152 -0
  11. package/dist/server/file_manager.d.ts +25 -0
  12. package/dist/server/file_manager.js +717 -0
  13. package/dist/server/http.js +248 -5
  14. package/dist/server/netpbm.d.ts +3 -0
  15. package/dist/server/netpbm.js +69 -0
  16. package/dist/server/pty.d.ts +26 -0
  17. package/dist/server/pty.js +150 -0
  18. package/dist/server/server.js +9 -2
  19. package/dist/server/session.d.ts +7 -1
  20. package/dist/server/session.js +67 -1
  21. package/dist/server/terminal_output.d.ts +25 -0
  22. package/dist/server/terminal_output.js +108 -0
  23. package/dist/server/terminals.d.ts +32 -0
  24. package/dist/server/terminals.js +366 -0
  25. package/dist/server/util.d.ts +4 -0
  26. package/dist/server/util.js +45 -1
  27. package/dist/shared/file_manager.d.ts +130 -0
  28. package/dist/shared/file_manager.js +7 -0
  29. package/dist/shared/protocol.d.ts +87 -2
  30. package/dist/shared/protocol.js +8 -0
  31. package/dist/types/client/api.d.ts +22 -0
  32. package/dist/types/client/connection.d.ts +22 -1
  33. package/dist/types/client/icons.d.ts +27 -0
  34. package/dist/types/client/sdk/index.d.ts +4 -3
  35. package/dist/types/shared/file_manager.d.ts +130 -0
  36. package/dist/types/shared/protocol.d.ts +87 -2
  37. package/dist/www/assets/Joystick.js +1 -1
  38. package/dist/www/assets/RobotModelView.js +2 -2
  39. package/dist/www/assets/TerminalView.css +1 -0
  40. package/dist/www/assets/TerminalView.js +17 -0
  41. package/dist/www/assets/dialogs.js +1 -0
  42. package/dist/www/assets/icons.js +1 -1
  43. package/dist/www/assets/index.css +1 -1
  44. package/dist/www/assets/index.js +59 -19
  45. package/dist/www/assets/keys.js +3 -0
  46. package/dist/www/assets/shared/tassello-sdk.js +1 -1
  47. package/dist/www/index.html +2 -0
  48. package/docs/plugins.md +20 -0
  49. package/package.json +6 -2
@@ -1,4 +1,5 @@
1
- import { existsSync } from 'node:fs';
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 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;
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 type ServerMessage = Hello | CommandStates | CommandUpdate | StreamStatus | TfUpdate | PathUpdate | TopicMessage | ServicesUpdate | ServiceResult | LogsUpdate | ArmUpdate | Result | PluginData | BehaviorTreeInfo | BehaviorTreeUpdate | BehaviorTreeRecording | BehaviorTreePlaybackState | BehaviorTreeFile | BehaviorTreeModels | RosoutUpdate | PanelsChanged | ErrorMessage;
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;
@@ -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;