green-screen-react 1.1.2 → 1.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/README.md +57 -0
- package/dist/index.d.mts +35 -5
- package/dist/index.d.ts +35 -5
- package/dist/index.js +577 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +577 -90
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +80 -35
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Multi-protocol legacy terminal React component. Connects to **TN5250** (IBM i /
|
|
|
4
4
|
|
|
5
5
|
[**Live Preview**](https://visionbridge-solutions.github.io/green-screen-react/)
|
|
6
6
|
|
|
7
|
+
> **v1.2.0**: per-field MDT state, `readMdt()` for cheap post-write verification, pluggable session store with `session.lost`/`session.resumed` lifecycle events, lower-level sign-on primitives. See the feature section below. Python integrators can use the new [`green-screen-client`](https://pypi.org/project/green-screen-client/) PyPI package.
|
|
8
|
+
|
|
7
9
|
## Install
|
|
8
10
|
|
|
9
11
|
```bash
|
|
@@ -83,12 +85,64 @@ class MyAdapter implements TerminalAdapter {
|
|
|
83
85
|
async getStatus() { /* ... */ }
|
|
84
86
|
async sendText(text: string) { /* ... */ }
|
|
85
87
|
async sendKey(key: string) { /* ... */ }
|
|
88
|
+
async setCursor?(row: number, col: number) { /* ... */ }
|
|
89
|
+
async readMdt?(modifiedOnly?: boolean) { /* ... */ } // v1.2.0
|
|
86
90
|
async connect(config?) { /* ... */ }
|
|
87
91
|
async disconnect() { /* ... */ }
|
|
88
92
|
async reconnect() { /* ... */ }
|
|
89
93
|
}
|
|
90
94
|
```
|
|
91
95
|
|
|
96
|
+
## v1.2.0 features
|
|
97
|
+
|
|
98
|
+
### Post-write verification with `readMdt()`
|
|
99
|
+
|
|
100
|
+
Instead of diffing the entire screen after a batch of writes, ask the proxy which fields actually captured input:
|
|
101
|
+
|
|
102
|
+
```tsx
|
|
103
|
+
import { WebSocketAdapter } from 'green-screen-react';
|
|
104
|
+
|
|
105
|
+
const adapter = new WebSocketAdapter({ workerUrl: 'http://localhost:3001' });
|
|
106
|
+
|
|
107
|
+
// ... after typing into several fields ...
|
|
108
|
+
const modified = await adapter.readMdt(); // only fields with MDT bit set
|
|
109
|
+
const all = await adapter.readMdt(false); // all input fields
|
|
110
|
+
|
|
111
|
+
for (const f of modified) {
|
|
112
|
+
console.log(`row ${f.row} col ${f.col}: "${f.value}"`);
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
`readMdt` is optional on the `TerminalAdapter` contract — protocols without a per-field modified concept (VT, HP6530) return `[]`.
|
|
117
|
+
|
|
118
|
+
### Session lifecycle events
|
|
119
|
+
|
|
120
|
+
`WebSocketAdapter` now exposes hooks for session-level transitions. Use them to prompt reconnect UX or surface a clean "session expired" state without string-matching errors:
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
const adapter = new WebSocketAdapter({ workerUrl: 'http://localhost:3001' });
|
|
124
|
+
|
|
125
|
+
adapter.onSessionLost((sessionId, status) => {
|
|
126
|
+
console.log('lost:', sessionId, status.error);
|
|
127
|
+
// show "Session expired, click to reconnect" UI
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
adapter.onSessionResumed((sessionId) => {
|
|
131
|
+
console.log('reattached:', sessionId);
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
On page reload, reattach to a session that survived the refresh:
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
const sessionId = localStorage.getItem('tn5250-session-id');
|
|
139
|
+
if (sessionId) {
|
|
140
|
+
await adapter.reattach(sessionId);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The proxy keeps the TCP connection alive across WebSocket drops within its idle timeout — `reattach` reconnects the WS and replays the current screen.
|
|
145
|
+
|
|
92
146
|
## Props
|
|
93
147
|
|
|
94
148
|
| Prop | Type | Default | Description |
|
|
@@ -106,6 +160,9 @@ class MyAdapter implements TerminalAdapter {
|
|
|
106
160
|
| `bootLoader` | `ReactNode \| false` | default | Custom boot loader |
|
|
107
161
|
| `onSignIn` | `(config) => void` | - | Sign-in callback |
|
|
108
162
|
| `onScreenChange` | `(screen) => void` | - | Screen change callback |
|
|
163
|
+
| `bootLoaderReady` | `boolean` | - | Explicit boot-loader dismissal (overrides default "dismiss on first screen"). |
|
|
164
|
+
| `headerRight` | `ReactNode` | - | Custom content in the header's right slot. |
|
|
165
|
+
| `statusActions` | `ReactNode` | - | Custom buttons rendered after connection status groups (e.g. disconnect button). |
|
|
109
166
|
| `className` | `string` | - | CSS class |
|
|
110
167
|
| `style` | `CSSProperties` | - | Inline styles |
|
|
111
168
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { ScreenData, ConnectionStatus, ConnectConfig, ProtocolType } from 'green-screen-types';
|
|
4
|
-
export { ConnectConfig, ConnectionStatus, Field, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
|
|
3
|
+
import { ScreenData, ConnectionStatus, FieldValue, ConnectConfig, ProtocolType } from 'green-screen-types';
|
|
4
|
+
export { ConnectConfig, ConnectionStatus, Field, FieldValue, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Protocol-specific color/rendering conventions.
|
|
@@ -67,6 +67,15 @@ interface TerminalAdapter {
|
|
|
67
67
|
sendKey(key: string): Promise<SendResult>;
|
|
68
68
|
/** Set cursor position (click-to-position) */
|
|
69
69
|
setCursor?(row: number, col: number): Promise<SendResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Read the current values of input fields, optionally restricted to the
|
|
72
|
+
* ones whose per-field modified-data-tag (MDT) bit is set. Used for cheap
|
|
73
|
+
* post-write verification: after entering a batch of field values, the
|
|
74
|
+
* caller can confirm what actually landed without re-reading the entire
|
|
75
|
+
* screen. Protocols without per-field MDT (VT, HP6530) return an empty
|
|
76
|
+
* array. Optional — adapters without this capability may omit it.
|
|
77
|
+
*/
|
|
78
|
+
readMdt?(modifiedOnly?: boolean): Promise<FieldValue[]>;
|
|
70
79
|
/** Establish a connection, optionally with sign-in config */
|
|
71
80
|
connect(config?: ConnectConfig): Promise<SendResult>;
|
|
72
81
|
/** Close the connection */
|
|
@@ -112,14 +121,18 @@ interface GreenScreenTerminalProps {
|
|
|
112
121
|
defaultProtocol?: ProtocolType;
|
|
113
122
|
/** Callback when sign-in form is submitted */
|
|
114
123
|
onSignIn?: (config: ConnectConfig) => void;
|
|
115
|
-
/** Show "press Enter to continue" hint after auto sign-in (for external adapter flows) */
|
|
116
|
-
autoSignedIn?: boolean;
|
|
117
124
|
/** Disable auto-focus on the terminal after connecting (default false) */
|
|
118
125
|
autoFocusDisabled?: boolean;
|
|
119
126
|
/** Custom boot loader element, or false to disable */
|
|
120
127
|
bootLoader?: React.ReactNode | false;
|
|
128
|
+
/** When true, dismiss the boot loader. If provided, overrides the default
|
|
129
|
+
* "dismiss when screen data arrives" behavior. Use to keep the boot loader
|
|
130
|
+
* visible during sign-in, startup command execution, etc. */
|
|
131
|
+
bootLoaderReady?: boolean;
|
|
121
132
|
/** Content for the right side of the header */
|
|
122
133
|
headerRight?: React.ReactNode;
|
|
134
|
+
/** Content rendered after the connection status groups (WiFi+host, Key+username) */
|
|
135
|
+
statusActions?: React.ReactNode;
|
|
123
136
|
/** Overlay content (e.g. "Extracting..." state) */
|
|
124
137
|
overlay?: React.ReactNode;
|
|
125
138
|
/** Callback for notifications (replaces toast) */
|
|
@@ -128,6 +141,8 @@ interface GreenScreenTerminalProps {
|
|
|
128
141
|
onScreenChange?: (screen: ScreenData) => void;
|
|
129
142
|
/** Callback for minimize action (embedded mode) */
|
|
130
143
|
onMinimize?: () => void;
|
|
144
|
+
/** Show the keyboard-shortcuts button in the header (default true) */
|
|
145
|
+
showShortcutsButton?: boolean;
|
|
131
146
|
/** Additional CSS class name */
|
|
132
147
|
className?: string;
|
|
133
148
|
/** Inline styles */
|
|
@@ -146,7 +161,7 @@ interface GreenScreenTerminalProps {
|
|
|
146
161
|
*
|
|
147
162
|
* Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
|
|
148
163
|
*/
|
|
149
|
-
declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn,
|
|
164
|
+
declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoFocusDisabled, bootLoader, bootLoaderReady, headerRight, statusActions, overlay, onNotification, onScreenChange, onMinimize, showShortcutsButton, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
|
|
150
165
|
|
|
151
166
|
interface TerminalBootLoaderProps {
|
|
152
167
|
/** Text to display during boot animation */
|
|
@@ -230,6 +245,7 @@ declare class RestAdapter implements TerminalAdapter {
|
|
|
230
245
|
sendText(text: string): Promise<SendResult>;
|
|
231
246
|
sendKey(key: string): Promise<SendResult>;
|
|
232
247
|
setCursor(row: number, col: number): Promise<SendResult>;
|
|
248
|
+
readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
|
|
233
249
|
connect(config?: ConnectConfig): Promise<SendResult>;
|
|
234
250
|
disconnect(): Promise<SendResult>;
|
|
235
251
|
reconnect(): Promise<SendResult>;
|
|
@@ -260,9 +276,12 @@ declare class WebSocketAdapter implements TerminalAdapter {
|
|
|
260
276
|
private status;
|
|
261
277
|
private pendingScreenResolver;
|
|
262
278
|
private pendingConnectResolver;
|
|
279
|
+
private pendingMdtResolver;
|
|
263
280
|
private connectingPromise;
|
|
264
281
|
private screenListeners;
|
|
265
282
|
private statusListeners;
|
|
283
|
+
private sessionLostListeners;
|
|
284
|
+
private sessionResumedListeners;
|
|
266
285
|
private _sessionId;
|
|
267
286
|
constructor(options?: WebSocketAdapterOptions);
|
|
268
287
|
private static detectEnvUrl;
|
|
@@ -272,11 +291,22 @@ declare class WebSocketAdapter implements TerminalAdapter {
|
|
|
272
291
|
onScreen(listener: (screen: ScreenData) => void): () => void;
|
|
273
292
|
/** Subscribe to status changes */
|
|
274
293
|
onStatus(listener: (status: ConnectionStatus) => void): () => void;
|
|
294
|
+
/**
|
|
295
|
+
* Subscribe to session-lost notifications. Fires when the proxy detects
|
|
296
|
+
* that the server-side session has terminated (host TCP drop, idle
|
|
297
|
+
* timeout, explicit destroy). Integrators use this to prompt a reconnect
|
|
298
|
+
* or swap to a "session expired" UI without relying on error-string
|
|
299
|
+
* matching.
|
|
300
|
+
*/
|
|
301
|
+
onSessionLost(listener: (sessionId: string, status: ConnectionStatus) => void): () => void;
|
|
302
|
+
/** Subscribe to session-resumed notifications (fires after a successful `reattach`). */
|
|
303
|
+
onSessionResumed(listener: (sessionId: string) => void): () => void;
|
|
275
304
|
getScreen(): Promise<ScreenData | null>;
|
|
276
305
|
getStatus(): Promise<ConnectionStatus>;
|
|
277
306
|
sendText(text: string): Promise<SendResult>;
|
|
278
307
|
sendKey(key: string): Promise<SendResult>;
|
|
279
308
|
setCursor(row: number, col: number): Promise<SendResult>;
|
|
309
|
+
readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
|
|
280
310
|
connect(config?: ConnectConfig): Promise<SendResult>;
|
|
281
311
|
/**
|
|
282
312
|
* Reattach to an existing proxy session (e.g. after page reload).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
import { ScreenData, ConnectionStatus, ConnectConfig, ProtocolType } from 'green-screen-types';
|
|
4
|
-
export { ConnectConfig, ConnectionStatus, Field, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
|
|
3
|
+
import { ScreenData, ConnectionStatus, FieldValue, ConnectConfig, ProtocolType } from 'green-screen-types';
|
|
4
|
+
export { ConnectConfig, ConnectionStatus, Field, FieldValue, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Protocol-specific color/rendering conventions.
|
|
@@ -67,6 +67,15 @@ interface TerminalAdapter {
|
|
|
67
67
|
sendKey(key: string): Promise<SendResult>;
|
|
68
68
|
/** Set cursor position (click-to-position) */
|
|
69
69
|
setCursor?(row: number, col: number): Promise<SendResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Read the current values of input fields, optionally restricted to the
|
|
72
|
+
* ones whose per-field modified-data-tag (MDT) bit is set. Used for cheap
|
|
73
|
+
* post-write verification: after entering a batch of field values, the
|
|
74
|
+
* caller can confirm what actually landed without re-reading the entire
|
|
75
|
+
* screen. Protocols without per-field MDT (VT, HP6530) return an empty
|
|
76
|
+
* array. Optional — adapters without this capability may omit it.
|
|
77
|
+
*/
|
|
78
|
+
readMdt?(modifiedOnly?: boolean): Promise<FieldValue[]>;
|
|
70
79
|
/** Establish a connection, optionally with sign-in config */
|
|
71
80
|
connect(config?: ConnectConfig): Promise<SendResult>;
|
|
72
81
|
/** Close the connection */
|
|
@@ -112,14 +121,18 @@ interface GreenScreenTerminalProps {
|
|
|
112
121
|
defaultProtocol?: ProtocolType;
|
|
113
122
|
/** Callback when sign-in form is submitted */
|
|
114
123
|
onSignIn?: (config: ConnectConfig) => void;
|
|
115
|
-
/** Show "press Enter to continue" hint after auto sign-in (for external adapter flows) */
|
|
116
|
-
autoSignedIn?: boolean;
|
|
117
124
|
/** Disable auto-focus on the terminal after connecting (default false) */
|
|
118
125
|
autoFocusDisabled?: boolean;
|
|
119
126
|
/** Custom boot loader element, or false to disable */
|
|
120
127
|
bootLoader?: React.ReactNode | false;
|
|
128
|
+
/** When true, dismiss the boot loader. If provided, overrides the default
|
|
129
|
+
* "dismiss when screen data arrives" behavior. Use to keep the boot loader
|
|
130
|
+
* visible during sign-in, startup command execution, etc. */
|
|
131
|
+
bootLoaderReady?: boolean;
|
|
121
132
|
/** Content for the right side of the header */
|
|
122
133
|
headerRight?: React.ReactNode;
|
|
134
|
+
/** Content rendered after the connection status groups (WiFi+host, Key+username) */
|
|
135
|
+
statusActions?: React.ReactNode;
|
|
123
136
|
/** Overlay content (e.g. "Extracting..." state) */
|
|
124
137
|
overlay?: React.ReactNode;
|
|
125
138
|
/** Callback for notifications (replaces toast) */
|
|
@@ -128,6 +141,8 @@ interface GreenScreenTerminalProps {
|
|
|
128
141
|
onScreenChange?: (screen: ScreenData) => void;
|
|
129
142
|
/** Callback for minimize action (embedded mode) */
|
|
130
143
|
onMinimize?: () => void;
|
|
144
|
+
/** Show the keyboard-shortcuts button in the header (default true) */
|
|
145
|
+
showShortcutsButton?: boolean;
|
|
131
146
|
/** Additional CSS class name */
|
|
132
147
|
className?: string;
|
|
133
148
|
/** Inline styles */
|
|
@@ -146,7 +161,7 @@ interface GreenScreenTerminalProps {
|
|
|
146
161
|
*
|
|
147
162
|
* Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
|
|
148
163
|
*/
|
|
149
|
-
declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn,
|
|
164
|
+
declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoFocusDisabled, bootLoader, bootLoaderReady, headerRight, statusActions, overlay, onNotification, onScreenChange, onMinimize, showShortcutsButton, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
|
|
150
165
|
|
|
151
166
|
interface TerminalBootLoaderProps {
|
|
152
167
|
/** Text to display during boot animation */
|
|
@@ -230,6 +245,7 @@ declare class RestAdapter implements TerminalAdapter {
|
|
|
230
245
|
sendText(text: string): Promise<SendResult>;
|
|
231
246
|
sendKey(key: string): Promise<SendResult>;
|
|
232
247
|
setCursor(row: number, col: number): Promise<SendResult>;
|
|
248
|
+
readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
|
|
233
249
|
connect(config?: ConnectConfig): Promise<SendResult>;
|
|
234
250
|
disconnect(): Promise<SendResult>;
|
|
235
251
|
reconnect(): Promise<SendResult>;
|
|
@@ -260,9 +276,12 @@ declare class WebSocketAdapter implements TerminalAdapter {
|
|
|
260
276
|
private status;
|
|
261
277
|
private pendingScreenResolver;
|
|
262
278
|
private pendingConnectResolver;
|
|
279
|
+
private pendingMdtResolver;
|
|
263
280
|
private connectingPromise;
|
|
264
281
|
private screenListeners;
|
|
265
282
|
private statusListeners;
|
|
283
|
+
private sessionLostListeners;
|
|
284
|
+
private sessionResumedListeners;
|
|
266
285
|
private _sessionId;
|
|
267
286
|
constructor(options?: WebSocketAdapterOptions);
|
|
268
287
|
private static detectEnvUrl;
|
|
@@ -272,11 +291,22 @@ declare class WebSocketAdapter implements TerminalAdapter {
|
|
|
272
291
|
onScreen(listener: (screen: ScreenData) => void): () => void;
|
|
273
292
|
/** Subscribe to status changes */
|
|
274
293
|
onStatus(listener: (status: ConnectionStatus) => void): () => void;
|
|
294
|
+
/**
|
|
295
|
+
* Subscribe to session-lost notifications. Fires when the proxy detects
|
|
296
|
+
* that the server-side session has terminated (host TCP drop, idle
|
|
297
|
+
* timeout, explicit destroy). Integrators use this to prompt a reconnect
|
|
298
|
+
* or swap to a "session expired" UI without relying on error-string
|
|
299
|
+
* matching.
|
|
300
|
+
*/
|
|
301
|
+
onSessionLost(listener: (sessionId: string, status: ConnectionStatus) => void): () => void;
|
|
302
|
+
/** Subscribe to session-resumed notifications (fires after a successful `reattach`). */
|
|
303
|
+
onSessionResumed(listener: (sessionId: string) => void): () => void;
|
|
275
304
|
getScreen(): Promise<ScreenData | null>;
|
|
276
305
|
getStatus(): Promise<ConnectionStatus>;
|
|
277
306
|
sendText(text: string): Promise<SendResult>;
|
|
278
307
|
sendKey(key: string): Promise<SendResult>;
|
|
279
308
|
setCursor(row: number, col: number): Promise<SendResult>;
|
|
309
|
+
readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
|
|
280
310
|
connect(config?: ConnectConfig): Promise<SendResult>;
|
|
281
311
|
/**
|
|
282
312
|
* Reattach to an existing proxy session (e.g. after page reload).
|