@bonsae/nrg 0.3.0 → 0.5.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.
@@ -1,17 +1,320 @@
1
1
  /**
2
2
  * Global type declarations for the Node-RED editor environment.
3
3
  * These are provided by Node-RED at runtime, not imported.
4
+ *
5
+ * Based on: https://github.com/GogoVega/node-red/blob/33d83d016a0c990c/packages/node_modules/%40node-red/editor-client/types/index.d.ts
4
6
  */
5
7
 
6
- // jQuery injected by Node-RED editor
7
- declare const $: any;
8
+ /// <reference types="jquery" />
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // jQuery Node-RED widget extensions
12
+ // ---------------------------------------------------------------------------
13
+
14
+ interface JQuery<TElement = HTMLElement> {
15
+ // Node-RED TypedInput widget
16
+ typedInput(options: NodeRED.TypedInputOptions): this;
17
+ typedInput(action: "value"): string;
18
+ typedInput(action: "value", value: string): void;
19
+ typedInput(action: "type"): string;
20
+ typedInput(action: "type", value: string): void;
21
+ typedInput(action: "types", value: any[]): void;
22
+ typedInput(action: "validate"): boolean;
23
+ typedInput(
24
+ action: "validate",
25
+ options: { returnErrorMessage: boolean },
26
+ ): string | boolean;
27
+ typedInput(action: "disable", value?: boolean): void;
28
+ typedInput(action: "enable"): void;
29
+ typedInput(action: "focus"): void;
30
+ typedInput(action: "hide"): void;
31
+ typedInput(action: "show"): void;
32
+ typedInput(action: "width", value: string | number): void;
33
+
34
+ // Node-RED i18n
35
+ i18n(): this;
36
+ }
37
+
38
+ // ---------------------------------------------------------------------------
39
+ // Node-RED editor types
40
+ // ---------------------------------------------------------------------------
41
+
42
+ declare namespace NodeRED {
43
+ type UID = string;
44
+
45
+ // -- Nodes --
46
+
47
+ interface BaseNode {
48
+ id: UID;
49
+ type: string;
50
+ changed: boolean;
51
+ z?: string;
52
+ _def: any;
53
+ [key: string]: any;
54
+ }
55
+
56
+ interface Node extends BaseNode {
57
+ x: number;
58
+ y: number;
59
+ w: number;
60
+ h: number;
61
+ name: string;
62
+ wires: UID[][];
63
+ inputs: number;
64
+ outputs: number;
65
+ g?: string;
66
+ _: (key: string) => string;
67
+ }
68
+
69
+ interface ConfigNode extends BaseNode {
70
+ name: string;
71
+ credentials?: Record<string, any>;
72
+ users: BaseNode[];
73
+ _def: {
74
+ category: "config";
75
+ [key: string]: any;
76
+ };
77
+ }
78
+
79
+ interface Link {
80
+ source: BaseNode;
81
+ target: BaseNode;
82
+ sourcePort: number;
83
+ }
84
+
85
+ interface Workspace {
86
+ id: UID;
87
+ type: "tab";
88
+ label: string;
89
+ disabled: boolean;
90
+ info: string;
91
+ }
92
+
93
+ // -- Editor --
94
+
95
+ interface EditorOptions {
96
+ id: string;
97
+ stateId?: string;
98
+ mode?: string;
99
+ value?: string;
100
+ focus?: boolean;
101
+ globals?: Record<string, boolean>;
102
+ }
103
+
104
+ interface TrayButton {
105
+ id?: string;
106
+ class?: string;
107
+ click?: (event: JQuery.ClickEvent) => void;
108
+ text?: string;
109
+ }
110
+
111
+ interface TrayOptions {
112
+ title?: string;
113
+ buttons?: TrayButton[];
114
+ focusElement?: boolean;
115
+ maximized?: boolean;
116
+ width?: "inherit" | number | string;
117
+ overlay?: boolean;
118
+ open?: (tray: JQuery, done?: () => void) => void;
119
+ close?: () => void;
120
+ resize?: (options: { width: number; height?: number }) => void;
121
+ show?: () => void;
122
+ }
123
+
124
+ // -- Popover --
125
+
126
+ interface PopoverOptions {
127
+ target: JQuery;
128
+ direction?: string;
129
+ trigger?: "hover" | "click" | "modal";
130
+ content: string | JQuery | (() => string | JQuery);
131
+ delay?: { show: number; hide: number };
132
+ autoClose?: number;
133
+ width?: number | string;
134
+ maxWidth?: number | string;
135
+ tooltip?: boolean;
136
+ interactive?: boolean;
137
+ class?: string;
138
+ }
139
+
140
+ interface PopoverInstance {
141
+ readonly element: JQuery | null;
142
+ close(instant?: boolean): PopoverInstance;
143
+ open(instant?: boolean): PopoverInstance;
144
+ setContent(content: PopoverOptions["content"]): PopoverInstance;
145
+ move(options: Partial<PopoverOptions>): void;
146
+ }
147
+
148
+ interface TooltipInstance extends PopoverInstance {
149
+ delete(): void;
150
+ setAction(action: string): void;
151
+ }
152
+
153
+ // -- Notifications --
154
+
155
+ interface NotificationOptions {
156
+ type?: "warning" | "compact" | "success" | "error";
157
+ fixed?: boolean;
158
+ modal?: boolean;
159
+ timeout?: number;
160
+ buttons?: Array<{
161
+ text: string;
162
+ class?: string;
163
+ click?: (event: JQuery.ClickEvent) => void;
164
+ }>;
165
+ id?: string;
166
+ }
167
+
168
+ interface NotificationElement {
169
+ update(msg: string | JQuery, options?: NotificationOptions): void;
170
+ close(): void;
171
+ }
172
+
173
+ // -- TypedInput --
174
+
175
+ type DefaultTypedInputType =
176
+ (typeof import("../constants").TYPED_INPUT_TYPES)[number];
177
+
178
+ interface TypedInputTypeDefinition {
179
+ value: string;
180
+ label?: string;
181
+ icon?: string;
182
+ hasValue?: boolean;
183
+ multiple?: boolean;
184
+ options?: string[] | Array<{ value: string; label: string }>;
185
+ validate?: ((value: string) => boolean) | RegExp;
186
+ valueLabel?: (container: JQuery, value: string) => void;
187
+ autoComplete?: (
188
+ value: string,
189
+ done: (result?: Array<{ value: string; label: string | JQuery }>) => void,
190
+ ) => void;
191
+ }
192
+
193
+ interface TypedInputOptions {
194
+ default?: DefaultTypedInputType | string;
195
+ types: Array<DefaultTypedInputType | TypedInputTypeDefinition>;
196
+ typeField?: JQuery.Selector | JQuery;
197
+ }
198
+ }
199
+
200
+ // ---------------------------------------------------------------------------
201
+ // RED global object
202
+ // ---------------------------------------------------------------------------
8
203
 
9
- // Node-RED editor API — injected by Node-RED editor
10
204
  declare const RED: {
205
+ /** Internationalization / translation function */
206
+ _: (key: string, substitutions?: Record<string, string>) => string;
207
+
208
+ /** Node management */
11
209
  nodes: {
12
210
  registerType(type: string, definition: any): void;
13
- node(id: string): any;
211
+ node(id: NodeRED.UID): NodeRED.BaseNode | null;
14
212
  dirty(): boolean;
213
+ dirty(dirty: boolean): void;
214
+ eachNode(callback: (node: NodeRED.Node) => void | false): void;
215
+ eachConfig(callback: (node: NodeRED.ConfigNode) => void | false): void;
216
+ filterNodes(filter: { z?: NodeRED.UID; type?: string }): NodeRED.BaseNode[];
217
+ filterLinks(filter: {
218
+ source?: NodeRED.BaseNode;
219
+ target?: NodeRED.BaseNode;
220
+ }): NodeRED.Link[];
221
+ getType(type: string): any;
222
+ id(): NodeRED.UID;
223
+ add(node: any): NodeRED.BaseNode;
224
+ remove(id: NodeRED.UID): {
225
+ links: NodeRED.Link[];
226
+ nodes: NodeRED.BaseNode[];
227
+ };
228
+ };
229
+
230
+ /** Code editor (ACE/Monaco) */
231
+ editor: {
232
+ createEditor(options: NodeRED.EditorOptions): any;
233
+ edit(node: NodeRED.Node, defaultTab?: any): void;
234
+ editConfig(
235
+ name: string,
236
+ type: string,
237
+ id: string,
238
+ prefix?: string,
239
+ editContext?: NodeRED.Node,
240
+ ): void;
241
+ prepareConfigNodeSelect(
242
+ node: NodeRED.BaseNode,
243
+ property: string,
244
+ type: string,
245
+ prefix?: string,
246
+ filter?: (configNode: NodeRED.ConfigNode) => boolean,
247
+ ): void;
248
+ validateNode(node: NodeRED.BaseNode): boolean;
249
+ };
250
+
251
+ /** Side panel tray */
252
+ tray: {
253
+ show(options: NodeRED.TrayOptions): void;
254
+ close(): void;
255
+ };
256
+
257
+ /** Popover / tooltip */
258
+ popover: {
259
+ create(options: NodeRED.PopoverOptions): NodeRED.PopoverInstance;
260
+ tooltip(
261
+ target: JQuery,
262
+ text: string,
263
+ direction?: string,
264
+ ): NodeRED.TooltipInstance;
265
+ };
266
+
267
+ /** Toast notifications */
268
+ notify(
269
+ message: string | JQuery,
270
+ options?: NodeRED.NotificationOptions,
271
+ ): NodeRED.NotificationElement;
272
+
273
+ /** Event system */
274
+ events: {
275
+ on(event: string, listener: (...args: any[]) => void): void;
276
+ off(event: string, listener: (...args: any[]) => void): void;
277
+ emit(event: string, ...args: any[]): void;
278
+ };
279
+
280
+ /** Undo/redo */
281
+ history: {
282
+ push(event: any): void;
283
+ pop(): any;
284
+ peek(): any;
285
+ list(): any[];
286
+ };
287
+
288
+ /** Keyboard shortcuts */
289
+ keyboard: {
290
+ add(scope: string, key: string, callback: () => void): void;
291
+ remove(key: string): void;
292
+ };
293
+
294
+ /** Runtime communication (WebSocket) */
295
+ comms: {
296
+ subscribe(topic: string, callback: (topic: string, msg: any) => void): void;
297
+ unsubscribe(
298
+ topic: string,
299
+ callback: (topic: string, msg: any) => void,
300
+ ): void;
301
+ };
302
+
303
+ /** Editor settings */
304
+ settings: {
305
+ get(key: string): any;
306
+ set(key: string, value: any): any;
307
+ remove(key: string): any;
308
+ [key: string]: any;
15
309
  };
310
+
311
+ /** Canvas view */
312
+ view: {
313
+ focus(): void;
314
+ selection(): { nodes?: NodeRED.Node[] };
315
+ redraw(updateActive?: boolean): void;
316
+ };
317
+
318
+ /** Catch-all for untyped properties */
16
319
  [key: string]: any;
17
320
  };
@@ -8,6 +8,7 @@ import NodeRedTypedInput from "./components/node-red-typed-input.vue";
8
8
  import NodeRedConfigInput from "./components/node-red-config-input.vue";
9
9
  import NodeRedSelectInput from "./components/node-red-select-input.vue";
10
10
  import NodeRedEditorInput from "./components/node-red-editor-input.vue";
11
+ import NodeRedInputLabel from "./components/node-red-input-label.vue";
11
12
  import NodeRedJsonSchemaForm from "./components/node-red-json-schema-form.vue";
12
13
 
13
14
  const _schemas: Record<string, any> = {};
@@ -163,6 +164,7 @@ function createNodeRedVueApp(
163
164
  features,
164
165
  });
165
166
 
167
+ app.component("NodeRedInputLabel", NodeRedInputLabel);
166
168
  app.component("NodeRedInput", NodeRedInput);
167
169
  app.component("NodeRedTypedInput", NodeRedTypedInput);
168
170
  app.component("NodeRedConfigInput", NodeRedConfigInput);
@@ -1,5 +1,5 @@
1
1
  import type { Schema } from "../schemas/types";
2
- import { type RED } from "../../server/types";
2
+ import { type RED, type NodeRedNode } from "../../server/types";
3
3
  import type {
4
4
  ConfigNodeContext,
5
5
  IONodeContext,
@@ -80,7 +80,7 @@ abstract class Node<TConfig = any, TCredentials = any, TSettings = any> {
80
80
  RED.log.info("Settings are valid");
81
81
  }
82
82
  protected readonly RED: RED;
83
- protected readonly node: any;
83
+ protected readonly node: NodeRedNode;
84
84
  protected readonly context!: ConfigNodeContext | IONodeContext;
85
85
  public readonly config!: NodeConfig<TConfig>;
86
86
 
@@ -89,7 +89,7 @@ abstract class Node<TConfig = any, TCredentials = any, TSettings = any> {
89
89
 
90
90
  constructor(
91
91
  RED: RED,
92
- node: any,
92
+ node: NodeRedNode,
93
93
  config: NodeConfig<TConfig>,
94
94
  credentials: NodeCredentials<TCredentials>,
95
95
  ) {
@@ -15,40 +15,26 @@ function NodeRef<T extends new (...args: any[]) => any>(
15
15
  options?: SchemaOptions,
16
16
  ): TNodeRef<InstanceType<T>> {
17
17
  return {
18
- ...SchemaType.String({
18
+ ...BaseType.String({
19
19
  description:
20
20
  options?.description || `Reference to ${(nodeClass as any).type}`,
21
21
  format: "node-id",
22
22
  }),
23
- "node-type": (nodeClass as any).type,
23
+ "x-nrg-node-type": (nodeClass as any).type,
24
24
  ...options,
25
25
  [Kind]: "NodeRef",
26
26
  } as unknown as TNodeRef<InstanceType<T>>;
27
27
  }
28
28
 
29
- function TypedInput(
30
- options?: SchemaOptions & { types?: string[] },
31
- ): TTypedInput {
32
- const { types, ...rest } = options ?? {};
29
+ function TypedInput(options?: SchemaOptions): TTypedInput {
33
30
  return {
34
31
  ...TypedInputSchema,
35
- ...rest,
36
- ...(types ? { "x-typed-types": types } : {}),
32
+ ...options,
37
33
  [Kind]: "TypedInput",
38
34
  } as unknown as TTypedInput;
39
35
  }
40
36
 
41
- const _OriginalString = BaseType.String.bind(BaseType);
42
- function StringWithLang(options?: SchemaOptions & { lang?: string }) {
43
- const { lang, ...rest } = options ?? {};
44
- return _OriginalString({
45
- ...rest,
46
- ...(lang ? { "x-editor-language": lang } : {}),
47
- });
48
- }
49
-
50
37
  const SchemaType = Object.assign({}, BaseType, {
51
- String: StringWithLang,
52
38
  NodeRef,
53
39
  TypedInput,
54
40
  });
@@ -62,7 +48,7 @@ function markNonValidatable<T extends TSchema>(schema: T): T {
62
48
 
63
49
  // NOTE: if the type is non serializable, like Functions or Constructor, we must skip validation and avoid applying defaults
64
50
  if (hasInvalidType) {
65
- (schema as any)["skip-validation"] = true;
51
+ (schema as any)["x-nrg-skip-validation"] = true;
66
52
 
67
53
  if ((schema as any).default !== undefined) {
68
54
  (schema as any)._default = (schema as any).default;
@@ -11,7 +11,7 @@ interface TNodeRef<T = any> extends TSchema {
11
11
  [Kind]: "NodeRef";
12
12
  static: T;
13
13
  type: "string";
14
- "node-type"?: string;
14
+ "x-nrg-node-type"?: string;
15
15
  }
16
16
 
17
17
  type ResolveNodeRefs<T> =
@@ -37,9 +37,17 @@ interface TTypedInput extends TSchema {
37
37
  };
38
38
  }
39
39
 
40
+ interface NrgFormOptions {
41
+ icon?: string;
42
+ typedInputTypes?: string[];
43
+ editorLanguage?: string;
44
+ }
45
+
40
46
  declare module "@sinclair/typebox" {
41
47
  interface SchemaOptions {
42
48
  exportable?: boolean;
49
+ "x-nrg-node-type"?: string;
50
+ "x-nrg-form"?: NrgFormOptions;
43
51
  }
44
52
  }
45
53