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
@@ -0,0 +1,3 @@
1
+ var e=`ESC /:\\ -:| HOME:~ UP END PGUP
2
+ TAB CTRL ALT LEFT DOWN RIGHT PGDN`,t={ESC:{label:`Esc`,title:`Escape`,plain:`\x1B`},TAB:{label:`Tab`,title:`Tab`,plain:` `},ENTER:{label:`⏎`,title:`Enter`,plain:`\r`},BKSP:{label:`⌫`,title:`Backspace`,plain:``,repeat:!0},SPACE:{label:`␣`,title:`Space`,plain:` `},INS:{label:`Ins`,title:`Insert`,tilde:2},DEL:{label:`Del`,title:`Delete`,tilde:3,repeat:!0},PGUP:{label:`PgUp`,title:`Page up`,tilde:5,repeat:!0},PGDN:{label:`PgDn`,title:`Page down`,tilde:6,repeat:!0},HOME:{label:`Home`,title:`Home`,final:`H`,cursor:!0},END:{label:`End`,title:`End`,final:`F`,cursor:!0},UP:{label:`↑`,title:`Up`,final:`A`,cursor:!0,repeat:!0},DOWN:{label:`↓`,title:`Down`,final:`B`,cursor:!0,repeat:!0},RIGHT:{label:`→`,title:`Right`,final:`C`,cursor:!0,repeat:!0},LEFT:{label:`←`,title:`Left`,final:`D`,cursor:!0,repeat:!0},F1:{label:`F1`,title:`F1`,final:`P`,ss3:!0},F2:{label:`F2`,title:`F2`,final:`Q`,ss3:!0},F3:{label:`F3`,title:`F3`,final:`R`,ss3:!0},F4:{label:`F4`,title:`F4`,final:`S`,ss3:!0},F5:{label:`F5`,title:`F5`,tilde:15},F6:{label:`F6`,title:`F6`,tilde:17},F7:{label:`F7`,title:`F7`,tilde:18},F8:{label:`F8`,title:`F8`,tilde:19},F9:{label:`F9`,title:`F9`,tilde:20},F10:{label:`F10`,title:`F10`,tilde:21},F11:{label:`F11`,title:`F11`,tilde:23},F12:{label:`F12`,title:`F12`,tilde:24}},n={CTRL:{modifier:`ctrl`,label:`Ctrl`,title:`Control: applies to the next key`},ALT:{modifier:`alt`,label:`Alt`,title:`Alt: applies to the next key`},SHIFT:{modifier:`shift`,label:`Shift`,title:`Shift: applies to the next key`}},r={KEYBOARD:{action:`keyboard`,label:`⌨`,title:`Show or hide the keyboard`},PASTE:{action:`paste`,label:`Paste`,title:`Paste`}};function i(e){let i=e.toUpperCase();if(n[i]){let{modifier:e,label:t,title:r}=n[i];return{label:t,title:r,modifier:e,repeat:!1,popup:null}}if(r[i]){let{action:e,label:t,title:n}=r[i];return{label:t,title:n,action:e,repeat:!1,popup:null}}if(t[i]){let{label:e,title:n,repeat:r=!1}=t[i];return{label:e,title:n,named:i,repeat:r,popup:null}}return{label:e,title:e,text:e,repeat:!1,popup:null}}function a(t){let n=t.split(`
3
+ `).map(e=>e.trim().split(/\s+/).filter(Boolean).map(e=>{let t=e.indexOf(`:`,1);if(t<0||t===e.length-1)return i(e);let n=i(e.slice(0,t)),r=i(e.slice(t+1));return n.modifier||r.modifier?n:{...n,popup:r}})).filter(e=>e.length>0);return n.length>0?n:a(e)}function o({ctrl:e,alt:t,shift:n}){return 1+ +!!n+(t?2:0)+(e?4:0)}function s(e){return e.ctrl||e.alt||e.shift}function c(e){if(e.length!==1)return null;let t=e.charCodeAt(0);if(e===``)return`\b`;if(t>=64&&t<=95||t>=97&&t<=122)return String.fromCharCode(t&31);let n={" ":0,2:0,3:27,4:28,5:29,6:30,7:31,"/":31,"-":31,8:127,"?":127};return e in n?String.fromCharCode(n[e]):null}function l(e,t){let[n=``]=e,r=e.slice(n.length),i=n;return t.shift&&(i=i.toUpperCase()),t.ctrl&&(i=c(i)??i),t.alt&&(i=`\x1b${i}`),i+r}function u(e,n,r){if(e.text!==void 0)return l(e.text,n);let i=e.named?t[e.named]:void 0;if(!i)return``;let a=o(n);return i.plain===void 0?i.tilde===void 0?a>1?`\x1b[1;${a}${i.final}`:i.ss3||i.cursor&&r?`\x1bO${i.final}`:`\x1b[${i.final}`:a>1?`\x1b[${i.tilde};${a}~`:`\x1b[${i.tilde}~`:i.plain===` `&&n.shift?n.alt?`\x1B\x1B[Z`:`\x1B[Z`:l(i.plain,n)}function d(e,t){if(!s(t)||!e)return null;if(!e.startsWith(`\x1B`))return l(e,t);let n=o(t),r=/^\x1b[[O]([A-DHFPQRS])$/.exec(e);if(r)return`\x1b[1;${n}${r[1]}`;let i=/^\x1b\[(\d+)~$/.exec(e);return i?`\x1b[${i[1]};${n}~`:null}export{d as i,u as n,a as r,e as t};
@@ -1 +1 @@
1
- import{$ as e,A as t,B as n,C as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,Q as _,R as v,S as y,T as b,U as x,V as S,W as C,X as w,Y as T,Z as E,_ as D,a as O,at as k,b as A,c as j,ct as M,d as N,et as P,f as F,g as I,h as L,i as R,it as z,j as B,k as V,l as H,m as U,n as W,nt as G,o as K,ot as q,p as J,q as Y,r as X,rt as Z,s as Q,st as $,t as ee,tt as te,u as ne,v as re,w as ie,x as ae,y as oe,z as se}from"../icons.js";import{a as ce,c as le,n as ue,r as de,s as fe,t as pe,u as me}from"../Joystick.js";export{ee as AngleIcon,W as AppsIcon,X as ArmIcon,R as ArrowDownToLineIcon,O as ArrowRightIcon,K as BanIcon,Q as BoltIcon,j as CameraIcon,H as CheckCircleIcon,ne as CloseIcon,N as CodeIcon,F as CopyIcon,J as CubeIcon,U as DesktopIcon,L as DiamondIcon,I as DownloadIcon,D as EyeIcon,re as EyeOffIcon,oe as FilmIcon,A as FilterIcon,ae as FitIcon,y as FlagIcon,r as ForkIcon,ie as GamepadIcon,b as HistoryIcon,a as ImageIcon,pe as Joystick,i as ListIcon,h as LocateIcon,V as LogsIcon,t as MapIcon,fe as Modal,B as MoreIcon,p as NavigationIcon,m as NodesIcon,g as ParallelIcon,o as PauseIcon,l as PencilIcon,f as PhoneIcon,v as PlayIcon,se as PlusIcon,n as PowerIcon,S as QuestionIcon,c as QuestionMarkIcon,x as RecordIcon,C as RedoIcon,s as RefreshIcon,d as RobotIcon,Y as SaveIcon,u as SearchIcon,T as SlidersIcon,w as StopIcon,E as TabletIcon,_ as TasselloIcon,e as TerminalIcon,P as TrashIcon,te as TreeEditIcon,G as TreeIcon,Z as UndoIcon,z as connection,ue as definePlugin,de as defineWidget,me as imageUrl,ce as notify,k as useCommandState,q as useConnectionStatus,le as useDialogs,$ as useTf,M as useTopic};
1
+ import{$ as e,A as t,At as n,B as r,C as i,Ct as a,D as o,Dt as s,E as c,Et as l,F as u,Ft as d,G as f,H as p,I as m,J as h,K as g,L as _,M as v,Mt as y,N as b,Nt as x,O as S,Ot as C,P as w,Pt as T,Q as E,R as D,S as O,St as k,T as A,Tt as j,U as M,V as N,W as P,X as F,Y as I,Z as L,_ as R,_t as z,a as B,at as V,b as H,bt as U,c as W,ct as G,d as K,dt as q,et as J,f as Y,ft as X,g as Z,gt as Q,h as $,ht as ee,i as te,it as ne,j as re,jt as ie,k as ae,kt as oe,l as se,lt as ce,m as le,mt as ue,n as de,nt as fe,o as pe,ot as me,p as he,pt as ge,q as _e,r as ve,rt as ye,s as be,st as xe,t as Se,tt as Ce,u as we,ut as Te,v as Ee,vt as De,w as Oe,wt as ke,x as Ae,xt as je,y as Me,yt as Ne,z as Pe}from"../icons.js";import{a as Fe,c as Ie,l as Le,n as Re,o as ze,r as Be,t as Ve}from"../Joystick.js";import{n as He,r as Ue}from"../dialogs.js";export{Se as AngleIcon,ze as ApiError,de as AppsIcon,ve as ArchiveIcon,te as ArmIcon,B as ArrowDownToLineIcon,pe as ArrowLeftIcon,be as ArrowRightIcon,W as ArrowUpIcon,se as BanIcon,we as BoltIcon,K as BookmarkIcon,Y as CameraIcon,he as CheckCircleIcon,le as ClipboardIcon,$ as CloseIcon,Z as CodeIcon,R as CopyIcon,Ee as CubeIcon,Me as DesktopIcon,H as DiagnosticsIcon,Ae as DiamondIcon,O as DownloadIcon,i as EyeIcon,Oe as EyeOffIcon,A as FileIcon,c as FilePlusIcon,o as FileTextIcon,S as FilmIcon,ae as FilterIcon,t as FitIcon,re as FlagIcon,v as FolderIcon,b as FolderPlusIcon,w as ForkIcon,u as GamepadIcon,m as HardDriveIcon,_ as HistoryIcon,D as HomeIcon,Pe as ImageIcon,r as InfoIcon,Ve as Joystick,N as KeyboardIcon,p as LinkIcon,M as ListIcon,P as LocateIcon,f as LockIcon,g as LogsIcon,_e as MapIcon,h as MaximizeIcon,I as MinimizeIcon,He as Modal,F as MoreIcon,L as NavigationIcon,E as NodesIcon,e as ParallelIcon,J as PauseIcon,Ce as PencilIcon,fe as PhoneIcon,ye as PieChartIcon,ne as PlayIcon,V as PlusIcon,me as PowerIcon,xe as QuestionIcon,G as QuestionMarkIcon,ce as RecordIcon,Te as RedoIcon,q as RefreshIcon,X as RobotIcon,ge as SaveIcon,ue as SearchIcon,ee as ShellIcon,Q as SidebarIcon,z as SlidersIcon,De as StopIcon,Ne as TabletIcon,U as TasselloIcon,je as TerminalIcon,k as TextLargerIcon,a as TextSmallerIcon,ke as TrashIcon,j as TreeEditIcon,l as TreeIcon,s as UndoIcon,C as UnfoldIcon,oe as UploadIcon,n as WrapIcon,ie as connection,Re as definePlugin,Be as defineWidget,Ie as fsApi,Le as imageUrl,Fe as notify,y as useCommandState,x as useConnectionStatus,Ue as useDialogs,T as useTf,d as useTopic};
@@ -27,6 +27,8 @@
27
27
  <link rel="modulepreload" crossorigin href="/assets/jsx-runtime.js">
28
28
  <link rel="modulepreload" crossorigin href="/assets/icons.js">
29
29
  <link rel="modulepreload" crossorigin href="/assets/Joystick.js">
30
+ <link rel="modulepreload" crossorigin href="/assets/dialogs.js">
31
+ <link rel="modulepreload" crossorigin href="/assets/keys.js">
30
32
  <link rel="stylesheet" crossorigin href="/assets/index.css">
31
33
  </head>
32
34
  <body>
package/docs/plugins.md CHANGED
@@ -157,10 +157,30 @@ mistyped values, so properties can be added without touching the saved panels),
157
157
  | `subscribeBehaviorTreePlayback({ bag, topic, tree }, handlers)` | A rosbag's log played back, as `subscribeBehaviorTree` follows a live one, with `playback(state)`: returns `{ id, unsubscribe }` |
158
158
  | `controlBehaviorTreePlayback(id, { playing?, speed?, time? })` | Plays, pauses, sets the speed of, or seeks the playback |
159
159
  | `subscribeRosout({ topic }, { update, status })` | The ROS log (`rcl_interfaces/msg/Log`, `topic` usually `/rosout`): the messages the server keeps, then the new ones, and the nodes of the ROS graph (see `RosoutUpdate` in `src/shared/protocol.ts`). Returns the unsubscribe function |
160
+ | `subscribeDiagnostics({ topic }, { update, status })` | The robot's diagnostics (`diagnostic_msgs/msg/DiagnosticArray`, `topic` usually `/diagnostics` or `/diagnostics_agg`): the statuses the server keeps, the latest of each name, stale once no longer received, and their latest changes of level, then those that changed (see `DiagnosticsUpdate` in `src/shared/protocol.ts`). Returns the unsubscribe function |
160
161
  | `subscribeBehaviorTreeFile({ path, libraries }, { file, models })` | A behavior tree's XML file: its text and version, again whenever it changes, and the node models it can use (Nav2's, its includes', the libraries') |
161
162
  | `saveBehaviorTreeFile(path, text, base, create?)` | Saves a behavior tree's XML file if still of the version `base` (`null`: whatever it is), or as a new file: resolves with `{ version, conflict }` |
163
+ | `subscribeTerminal({ terminal, command, folder }, { output, exit, status, shown })` | A terminal on the robot, by a name of the page's choosing: the login shell, or `command`, in `folder`. Its output as it comes (`TerminalOutput`: written to a terminal emulator, then acknowledged), from what the page shows, which `shown()` gives on every connection: `{ cols, rows, started, offset }`. Returns `{ id, unsubscribe }`; the terminal lives on without the page, for an hour. The dashboard's own pages only |
164
+ | `terminalInput(id, data)` / `resizeTerminal(id, cols, rows)` | What is typed in the terminal; its size |
165
+ | `ackTerminal(id, started, offset)` | The page wrote the output up to `offset`: the server sends at most 256 KB ahead of it |
166
+ | `restartTerminal(id)` | Hangs up the terminal's program, and starts it again |
162
167
  | `serverNow()` | Now, on the robot's clock |
163
168
 
169
+ The robot's files, as the File Manager widget has them (its REST API, `/api/fs`, see
170
+ `src/shared/file_manager.ts`): `fsApi`. Reads resolve with what the server says, changes with
171
+ `{ paths, conflicts }`, and failures reject with an `ApiError`, which has the HTTP `status`.
172
+
173
+ | | |
174
+ |---|---|
175
+ | `fsApi.list(path, known?)` | A folder's entries (`FsListing`); `undefined` while still the `known` version, for polling |
176
+ | `fsApi.details(path)` | An entry's kind, size, times, owner, permissions, link and disk (`FsDetails`) |
177
+ | `fsApi.disks()` | The robot's file systems, their size and free space (`FsDisk[]`) |
178
+ | `fsApi.analyze(path)` | What takes a folder's space (`FsAnalysis`) |
179
+ | `fsApi.readText(path, stamp?)` / `fsApi.saveText(path, text, base, create?)` | A text file and its version; saved only if still of the version `base` (`null`: whatever it is), else `{ conflict: true }` |
180
+ | `fsApi.operate(operation)` | `mkdir`, `create`, `rename`, `move`, `copy`, `delete`, `chmod` (`FsOperation`). Moves and copies with `conflict: 'ask'` do nothing while names are taken, and say which |
181
+ | `fsApi.upload(folder, name, file, conflict, onProgress)` | Uploads a `Blob`: `{ result, abort }` |
182
+ | `fsApi.downloadUrl(paths)` / `fsApi.viewUrl(path)` | A file to download (folders, and several entries, as a `.tar.gz`); an image to show (PGM maps as PNG) |
183
+
164
184
  Messages are JSON as rclnodejs has them: fields by name, numeric arrays as arrays, 64 bit
165
185
  integers as numbers. Subscriptions survive reconnections: they are renewed when the page
166
186
  reconnects. Requests and calls reject when the page is not connected.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tassello",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Web dashboard for ROS 2 robots: panels of widgets arranged in the browser, on any device, extensible with plugins",
5
5
  "keywords": [
6
6
  "ros",
@@ -68,9 +68,10 @@
68
68
  "prepack": "npm run typecheck && npm test && npm run build"
69
69
  },
70
70
  "dependencies": {
71
+ "@xterm/addon-serialize": "^0.14.0",
72
+ "@xterm/headless": "^6.0.0",
71
73
  "rclnodejs": "^2.3.0",
72
74
  "sharp": "^0.35.5",
73
- "tassello": "^0.1.1",
74
75
  "ws": "^8.22.0"
75
76
  },
76
77
  "peerDependencies": {
@@ -88,6 +89,9 @@
88
89
  "@types/three": "^0.186.0",
89
90
  "@types/ws": "^8.18.2",
90
91
  "@vitejs/plugin-react": "^6.1.2",
92
+ "@xterm/addon-fit": "^0.11.0",
93
+ "@xterm/addon-web-links": "^0.12.0",
94
+ "@xterm/xterm": "^6.0.0",
91
95
  "react": "^19.3.0",
92
96
  "react-dom": "^19.3.0",
93
97
  "three": "^0.186.1",