@theotherwillembotha/node-red-plugincore 0.0.55 → 0.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.
Files changed (158) hide show
  1. package/README.md +616 -217
  2. package/build/GenerateNodes.js +3 -6
  3. package/build/Nodes.html +3 -1502
  4. package/build/Nodes.js +5 -15
  5. package/build/Plugins.html +227 -0
  6. package/build/Plugins.js +18 -9
  7. package/build/core/NodeConstructor.d.ts +10 -16
  8. package/build/core/NodeConstructor.d.ts.map +1 -1
  9. package/build/core/NodeConstructor.js +112 -156
  10. package/build/core/NodeGenerator.d.ts.map +1 -1
  11. package/build/core/NodeGenerator.js +79 -29
  12. package/build/core/NodeManagerRuntime.d.ts +44 -0
  13. package/build/core/NodeManagerRuntime.d.ts.map +1 -0
  14. package/build/core/NodeManagerRuntime.js +140 -0
  15. package/build/core/Utils.d.ts.map +1 -1
  16. package/build/core/logger/service/LoggerService.d.ts +6 -5
  17. package/build/core/logger/service/LoggerService.d.ts.map +1 -1
  18. package/build/core/logger/service/LoggerService.js +51 -20
  19. package/build/core/logger/template/LoggerTemplate.d.ts.map +1 -1
  20. package/build/core/metrics/MetricsDecorator.d.ts +1 -2
  21. package/build/core/metrics/MetricsDecorator.d.ts.map +1 -1
  22. package/build/core/metrics/MetricsDecorator.js +89 -116
  23. package/build/core/metrics/node/CounterMetricConfigNode.d.ts.map +1 -1
  24. package/build/core/metrics/node/CounterMetricConfigNode.js +4 -5
  25. package/build/core/metrics/node/GaugeMetricConfigNode.d.ts.map +1 -1
  26. package/build/core/metrics/node/GaugeMetricConfigNode.js +5 -6
  27. package/build/core/metrics/node/MetricsConfigNode.d.ts +19 -9
  28. package/build/core/metrics/node/MetricsConfigNode.d.ts.map +1 -1
  29. package/build/core/metrics/node/MetricsConfigNode.js +14 -45
  30. package/build/core/metrics/node/TimerMetricConfigNode.d.ts.map +1 -1
  31. package/build/core/metrics/node/TimerMetricConfigNode.js +11 -17
  32. package/build/core/metrics/service/MetricsService.d.ts +110 -114
  33. package/build/core/metrics/service/MetricsService.d.ts.map +1 -1
  34. package/build/core/metrics/service/MetricsService.js +122 -339
  35. package/build/core/metrics/template/CounterMetricTemplate.d.ts.map +1 -1
  36. package/build/core/metrics/template/GaugeMetricTemplate.d.ts.map +1 -1
  37. package/build/core/metrics/template/MetricsTemplate.d.ts.map +1 -1
  38. package/build/core/metrics/template/MetricsTemplate.js +1 -2
  39. package/build/core/metrics/template/TimerMetricTemplate.d.ts.map +1 -1
  40. package/build/core/other/node/DelegatedConfigReferenceNode.d.ts +1 -1
  41. package/build/core/other/node/DelegatedConfigReferenceNode.d.ts.map +1 -1
  42. package/build/core/other/node/DelegatedConfigReferenceNode.js +1 -1
  43. package/build/core/other/service/InputService.d.ts.map +1 -1
  44. package/build/core/other/service/SettingsService.d.ts +1 -2
  45. package/build/core/other/service/SettingsService.d.ts.map +1 -1
  46. package/build/core/other/service/SettingsService.js +19 -5
  47. package/build/core/other/template/BasicTemplate.d.ts.map +1 -1
  48. package/build/core/other/template/SettingsTemplate.d.ts.map +1 -1
  49. package/build/core/state/node/InternalStateConfigNode.d.ts +16 -0
  50. package/build/core/state/node/InternalStateConfigNode.d.ts.map +1 -0
  51. package/build/core/state/node/InternalStateConfigNode.js +89 -0
  52. package/build/core/state/node/StateConfigNode.d.ts +24 -0
  53. package/build/core/state/node/StateConfigNode.d.ts.map +1 -0
  54. package/build/core/state/node/StateConfigNode.js +22 -0
  55. package/build/core/state/service/StateService.d.ts +34 -0
  56. package/build/core/state/service/StateService.d.ts.map +1 -0
  57. package/build/core/state/service/StateService.js +201 -0
  58. package/build/core/state/template/StateTemplate.d.ts +8 -0
  59. package/build/core/state/template/StateTemplate.d.ts.map +1 -0
  60. package/build/core/state/template/StateTemplate.js +11 -0
  61. package/build/core/tagging/ServiceDescriptionDecorator.d.ts +10 -0
  62. package/build/core/tagging/ServiceDescriptionDecorator.d.ts.map +1 -0
  63. package/build/core/tagging/ServiceDescriptionDecorator.js +10 -0
  64. package/build/core/tagging/service/NodeTypeService.d.ts +1 -2
  65. package/build/core/tagging/service/NodeTypeService.d.ts.map +1 -1
  66. package/build/core/tagging/service/NodeTypeService.js +19 -5
  67. package/build/core/ui/template/ScriptEditorTemplate.d.ts.map +1 -1
  68. package/build/core/ui/template/UIHelperTemplate.d.ts.map +1 -1
  69. package/build/core/webhook/WebhookDecorator.d.ts.map +1 -1
  70. package/build/core/webhook/WebhookDecorator.js +43 -6
  71. package/build/core/webhook/node/WebhookServerConfigNode.d.ts.map +1 -1
  72. package/build/core/webhook/service/ReverseProxyTypeService.d.ts +1 -0
  73. package/build/core/webhook/service/ReverseProxyTypeService.d.ts.map +1 -1
  74. package/build/core/webhook/service/WebhookServerService.d.ts +3 -4
  75. package/build/core/webhook/service/WebhookServerService.d.ts.map +1 -1
  76. package/build/core/webhook/service/WebhookServerService.js +48 -23
  77. package/build/core/webhook/template/WebhookTemplate.d.ts.map +1 -1
  78. package/build/index.d.ts +5 -2
  79. package/build/index.d.ts.map +1 -1
  80. package/build/index.js +6 -2
  81. package/build/runtime/NodeManagerRuntime.js +140 -0
  82. package/documentation/CounterMetricConfigNode.png +0 -0
  83. package/documentation/GaugeMetricConfigNode.png +0 -0
  84. package/documentation/LoggerTemplate.png +0 -0
  85. package/documentation/MetricsTemplate.png +0 -0
  86. package/documentation/StateTemplate.png +0 -0
  87. package/documentation/TimerMetricConfigNode_histogram.png +0 -0
  88. package/documentation/TimerMetricConfigNode_summary.png +0 -0
  89. package/documentation/WebhookServerConfigNode.png +0 -0
  90. package/documentation/WebhookTemplate.png +0 -0
  91. package/package.json +5 -12
  92. package/src/GenerateNodes.ts +7 -11
  93. package/src/core/NodeConstructor.ts +134 -197
  94. package/src/core/NodeGenerator.ts +88 -34
  95. package/src/core/NodeManagerRuntime.ts +179 -0
  96. package/src/core/logger/service/LoggerService.ts +39 -26
  97. package/src/core/logger/template/LoggerTemplate.html +13 -8
  98. package/src/core/metrics/MetricsDecorator.ts +140 -168
  99. package/src/core/metrics/node/CounterMetricConfigNode.ts +20 -20
  100. package/src/core/metrics/node/GaugeMetricConfigNode.ts +24 -25
  101. package/src/core/metrics/node/MetricsConfigNode.ts +29 -48
  102. package/src/core/metrics/node/TimerMetricConfigNode.html +2 -2
  103. package/src/core/metrics/node/TimerMetricConfigNode.ts +50 -59
  104. package/src/core/metrics/service/MetricsService.ts +214 -489
  105. package/src/core/metrics/template/CounterMetricTemplate.html +0 -1
  106. package/src/core/metrics/template/GaugeMetricTemplate.html +1 -1
  107. package/src/core/metrics/template/MetricsTemplate.html +132 -13
  108. package/src/core/metrics/template/MetricsTemplate.ts +3 -4
  109. package/src/core/other/node/DelegatedConfigReferenceNode.ts +1 -1
  110. package/src/core/other/service/SettingsService.ts +6 -10
  111. package/src/core/other/template/BasicTemplate.html +5 -2
  112. package/src/core/state/node/InternalStateConfigNode.html +77 -0
  113. package/src/core/state/node/InternalStateConfigNode.ts +102 -0
  114. package/src/core/state/node/StateConfigNode.ts +29 -0
  115. package/src/core/state/service/StateService.ts +180 -0
  116. package/src/core/state/template/StateTemplate.html +244 -0
  117. package/src/core/state/template/StateTemplate.ts +17 -0
  118. package/src/core/tagging/ServiceDescriptionDecorator.ts +23 -0
  119. package/src/core/tagging/service/NodeTypeService.ts +6 -11
  120. package/src/core/ui/template/UIHelperTemplate.html +41 -26
  121. package/src/core/webhook/WebhookDecorator.ts +53 -10
  122. package/src/core/webhook/service/ReverseProxyTypeService.ts +1 -0
  123. package/src/core/webhook/service/WebhookServerService.ts +39 -28
  124. package/src/core/webhook/template/WebhookTemplate.html +29 -36
  125. package/src/index.ts +7 -2
  126. package/build/core/logger/node/ConsoleLoggerConfigNode.d.ts +0 -20
  127. package/build/core/logger/node/ConsoleLoggerConfigNode.d.ts.map +0 -1
  128. package/build/core/logger/node/ConsoleLoggerConfigNode.html +0 -90
  129. package/build/core/logger/node/ConsoleLoggerConfigNode.js +0 -62
  130. package/build/core/logger/node/RestLoggerConfigNode.d.ts +0 -40
  131. package/build/core/logger/node/RestLoggerConfigNode.d.ts.map +0 -1
  132. package/build/core/logger/node/RestLoggerConfigNode.html +0 -183
  133. package/build/core/logger/node/RestLoggerConfigNode.js +0 -128
  134. package/build/core/logger/template/LoggerTemplate.html +0 -331
  135. package/build/core/metrics/node/CounterMetricConfigNode.html +0 -48
  136. package/build/core/metrics/node/GaugeMetricConfigNode.html +0 -48
  137. package/build/core/metrics/node/MetricsConfigNode.html +0 -21
  138. package/build/core/metrics/node/TimerMetricConfigNode.html +0 -190
  139. package/build/core/metrics/template/CounterMetricTemplate.html +0 -40
  140. package/build/core/metrics/template/GaugeMetricTemplate.html +0 -39
  141. package/build/core/metrics/template/MetricsTemplate.html +0 -54
  142. package/build/core/metrics/template/TimerMetricTemplate.html +0 -39
  143. package/build/core/other/node/DelegatedConfigReferenceNode.html +0 -1
  144. package/build/core/other/template/BasicTemplate.html +0 -76
  145. package/build/core/other/template/SettingsTemplate.html +0 -128
  146. package/build/core/ui/template/ScriptEditorTemplate.html +0 -50
  147. package/build/core/ui/template/UIHelperTemplate.html +0 -229
  148. package/build/core/webhook/node/WebhookServerConfigNode.html +0 -61
  149. package/build/core/webhook/template/WebhookTemplate.html +0 -442
  150. package/documentation/ConsoleLoggerConfigNode.png +0 -0
  151. package/documentation/MetricsConfigNode.png +0 -0
  152. package/documentation/RestLoggerConfigNode.png +0 -0
  153. package/documentation/TimerMetricConfigNode.png +0 -0
  154. package/documentation/WebhookNode.png +0 -0
  155. package/src/core/logger/node/ConsoleLoggerConfigNode.html +0 -90
  156. package/src/core/logger/node/ConsoleLoggerConfigNode.ts +0 -71
  157. package/src/core/logger/node/RestLoggerConfigNode.html +0 -183
  158. package/src/core/logger/node/RestLoggerConfigNode.ts +0 -170
@@ -0,0 +1,179 @@
1
+ /**
2
+ * NodeManagerRuntime.ts
3
+ *
4
+ * STANDALONE - zero imports from the rest of plugincore.
5
+ *
6
+ * This file is compiled and copied into every plugin's build output so that
7
+ * plugins are self-contained and do not require plugincore to be separately
8
+ * installed in the user's Node-RED environment.
9
+ *
10
+ * When multiple plugins are deployed, each ships its own copy of this file.
11
+ * The first plugin to load registers its NodeManager and nodes; subsequent
12
+ * copies operate independently on their own node types with no conflict.
13
+ *
14
+ * POST_CONSTRUCT_KEY is intentionally a plain string (not a Symbol) so that
15
+ * the decorators (from plugincore's NodeConstructor, loaded via the plugin's
16
+ * dependency on plugincore) and this runtime file (a separate module instance)
17
+ * resolve to the same property key on node instances.
18
+ */
19
+
20
+ import type { NodeAPI, NodeAPISettingsWithData } from "node-red";
21
+
22
+ // ─── API version ────────────────────────────────────────────────────────────
23
+ // Semver of the NodeManager API contract - independent of plugincore's package
24
+ // version. Bump when the contract changes; plugins can read this to warn users
25
+ // that they were built against a different NodeManager version.
26
+ export const NODEMANAGER_API_VERSION = "1.0.0";
27
+
28
+ // ─── Shared key for post-construct initializer lists ────────────────────────
29
+ // Must be a plain string so it resolves identically across module instances.
30
+ export const POST_CONSTRUCT_KEY = '__plugincore_postConstructInitializers__';
31
+
32
+ // ─── Minimal types ───────────────────────────────────────────────────────────
33
+
34
+ export interface BaseNodeConfig {
35
+ id: string;
36
+ name: string;
37
+ type: string;
38
+ }
39
+
40
+ interface INodeDescriptor {
41
+ id(): string;
42
+ tags(): string[];
43
+ }
44
+
45
+ interface INodeClass {
46
+ new(node: any, config: any): any;
47
+ getNodeDescriptor(): INodeDescriptor;
48
+ }
49
+
50
+ // ─── Post-construct initializer runner ───────────────────────────────────────
51
+
52
+ export function runPostConstructInitializers(instance: any): void {
53
+ const initializers: Function[] = instance[POST_CONSTRUCT_KEY];
54
+ if (!initializers || initializers.length === 0) return;
55
+
56
+ const className = instance.constructor.name;
57
+ initializers.forEach((init, index) => {
58
+ try {
59
+ init(instance);
60
+ } catch (error) {
61
+ console.error(
62
+ `Post-construct initialization failed:\n` +
63
+ ` Class: ${className}\n` +
64
+ ` Initializer: ${index + 1}/${initializers.length}\n` +
65
+ ` Error: ${error instanceof Error ? error.message : String(error)}`
66
+ );
67
+ throw error;
68
+ }
69
+ });
70
+
71
+ delete instance[POST_CONSTRUCT_KEY];
72
+ }
73
+
74
+ // ─── NodeManager ─────────────────────────────────────────────────────────────
75
+ // RED is stored on `global` rather than as a static class field so that all
76
+ // module instances of NodeManagerRuntime (the local copy bundled into Nodes.js
77
+ // and the copy bundled via plugincore's NodeConstructor) share the same value.
78
+ // Without this, esbuild's two separate inline copies would have independent
79
+ // static fields and the one used by decorators would never see RED being set.
80
+ const _GLOBAL_RED_KEY = '__plugincore_NodeManager_RED__';
81
+
82
+ // ─── Global node-type registration guard ─────────────────────────────────────
83
+ // When multiple self-contained plugins are installed they each bundle plugincore
84
+ // inline and each try to call RED.nodes.registerType for the same shared
85
+ // infrastructure node types (ConsoleLoggerConfigNode, RestLoggerConfigNode, etc.).
86
+ // Node-RED rejects duplicate registrations with a warning and the second
87
+ // plugin's Nodes.js fails to load. This global set tracks which types have
88
+ // already been registered so subsequent plugins silently skip them.
89
+ const _GLOBAL_REGISTERED_NODES_KEY = '__plugincore_registered_nodes__';
90
+
91
+ function getRegisteredNodes(): Set<string> {
92
+ if (!(global as any)[_GLOBAL_REGISTERED_NODES_KEY]) {
93
+ (global as any)[_GLOBAL_REGISTERED_NODES_KEY] = new Set<string>();
94
+ }
95
+ return (global as any)[_GLOBAL_REGISTERED_NODES_KEY];
96
+ }
97
+
98
+ export class NodeManager {
99
+
100
+ // nodeTypeService is resolved dynamically via RED.plugins - no static import needed.
101
+ private nodeTypeService: any;
102
+ private typeBacklog: INodeClass[] = [];
103
+
104
+ public constructor(RED: NodeAPI<NodeAPISettingsWithData>) {
105
+ (global as any)[_GLOBAL_RED_KEY] = RED;
106
+
107
+ const nodeTypeServiceId = "@theotherwillembotha/nodetypeservice";
108
+
109
+ const nodeTypeServiceListener = (pluginID: string) => {
110
+ if (pluginID === nodeTypeServiceId) {
111
+ RED.events.off('plugin.instantiated', nodeTypeServiceListener);
112
+ this.nodeTypeService = (RED.plugins.get(nodeTypeServiceId) as any).instance;
113
+
114
+ for (const nodeType of this.typeBacklog) {
115
+ for (const tag of nodeType.getNodeDescriptor().tags()) {
116
+ this.nodeTypeService.registerNodeType(tag, nodeType);
117
+ }
118
+ }
119
+ this.typeBacklog = [];
120
+ }
121
+ };
122
+
123
+ this.nodeTypeService = (RED.plugins.get(nodeTypeServiceId) as any)?.instance;
124
+ if (!this.nodeTypeService) {
125
+ RED.events.on('plugin.instantiated', nodeTypeServiceListener);
126
+ }
127
+ }
128
+
129
+ public static get RED(): NodeAPI<NodeAPISettingsWithData> {
130
+ return (global as any)[_GLOBAL_RED_KEY];
131
+ }
132
+
133
+ public registerNodeType(typeName: string, type: INodeClass): NodeManager {
134
+ if (!type) {
135
+ console.error(
136
+ `[NodeManager v${NODEMANAGER_API_VERSION}] Type "${typeName}" is undefined. ` +
137
+ `Ensure it is exported and included in GenerateNodes.`
138
+ );
139
+ return this;
140
+ }
141
+
142
+ const registeredNodes = getRegisteredNodes();
143
+ if (registeredNodes.has(typeName)) {
144
+ // Already registered by another plugin - skip to avoid Node-RED duplicate-registration error.
145
+ return this;
146
+ }
147
+ registeredNodes.add(typeName);
148
+
149
+ const nodeConstructor = function(this: any, config: any) {
150
+ try {
151
+ NodeManager.RED.nodes.createNode(this, config);
152
+ const node = new (type as any)(this, config);
153
+ runPostConstructInitializers(node);
154
+ if (node.onInit) {
155
+ node.onInit();
156
+ }
157
+ } catch (error) {
158
+ console.error(`[NodeManager v${NODEMANAGER_API_VERSION}] Failed to construct node "${typeName}":`, error);
159
+ }
160
+ };
161
+
162
+ try {
163
+ NodeManager.RED.nodes.registerType(typeName, nodeConstructor, { settings: {} });
164
+
165
+ const nodeDescription = type.getNodeDescriptor();
166
+ if (this.nodeTypeService) {
167
+ for (const tag of nodeDescription.tags()) {
168
+ this.nodeTypeService.registerNodeType(tag, type);
169
+ }
170
+ } else {
171
+ this.typeBacklog.push(type);
172
+ }
173
+ } catch (error) {
174
+ console.error(`[NodeManager v${NODEMANAGER_API_VERSION}] Failed to register node type "${typeName}":`, error);
175
+ }
176
+
177
+ return this;
178
+ }
179
+ }
@@ -1,15 +1,23 @@
1
1
 
2
- import {BaseService, ServiceDescriptor, ConfigNodeConfig, ConfigNode } from "../../NodeConstructor";
2
+ import {BaseService, ConfigNodeConfig, ConfigNode } from "../../NodeConstructor";
3
+ import { ServiceDescription } from "../../tagging/ServiceDescriptionDecorator";
3
4
  import { NodeAPI, NodeAPISettingsWithData, Node } from "node-red";
4
- import Handlebars from "handlebars";
5
5
  import { LoggerTemplate, LoggerTemplateConfig } from "../template/LoggerTemplate";
6
- var network = require('network');
7
6
 
8
- // helper for serializing json objects inside handlebars tags.
9
- // you can then convert it like this: {{{json myobject}}}
10
- Handlebars.registerHelper('json', function(context) {
11
- return JSON.stringify(context);
12
- });
7
+ // Build-time / optional runtime deps - lazy so they are never required at bundle load time.
8
+ function getHandlebars(): any { return require('handlebars'); }
9
+ function getNetwork(): any { return require('network'); }
10
+
11
+ let _helpersRegistered = false;
12
+ function ensureHelpersRegistered(): void {
13
+ if (_helpersRegistered) return;
14
+ _helpersRegistered = true;
15
+ // helper for serializing json objects inside handlebars tags.
16
+ // you can then convert it like this: {{{json myobject}}}
17
+ getHandlebars().registerHelper('json', function(context: any) {
18
+ return JSON.stringify(context);
19
+ });
20
+ }
13
21
 
14
22
  export enum Level{
15
23
  DEBUG = "DEBUG",
@@ -40,12 +48,13 @@ export type TagMap = {
40
48
 
41
49
  export abstract class Log {
42
50
  private _config: LoggerTemplateConfig;
43
- private template: HandlebarsTemplateDelegate<any>;
51
+ private _templateStr: string;
52
+ private _compiledTemplate: any = null;
44
53
  private tags:TagMap;
45
54
 
46
55
  protected constructor(config:LoggerTemplateConfig){
47
56
  this._config = config;
48
- this.template = Handlebars.compile(config.template);
57
+ this._templateStr = config.template;
49
58
  this.tags = {
50
59
  id: config.id,
51
60
  node: config.name,
@@ -55,6 +64,14 @@ export abstract class Log {
55
64
  }
56
65
  }
57
66
 
67
+ private getTemplate(): any {
68
+ if (!this._compiledTemplate) {
69
+ ensureHelpersRegistered();
70
+ this._compiledTemplate = getHandlebars().compile(this._templateStr);
71
+ }
72
+ return this._compiledTemplate;
73
+ }
74
+
58
75
  protected config():LoggerTemplateConfig{
59
76
  return this._config;
60
77
  }
@@ -62,7 +79,7 @@ export abstract class Log {
62
79
  public log(payload:{[key:string]:any}|string):void{
63
80
  try{
64
81
  // step 1. serialize the payload using the template engine.
65
- let message = (payload instanceof String) ? payload as string : this.template({msg:payload});
82
+ let message = (payload instanceof String) ? payload as string : this.getTemplate()({msg:payload});
66
83
 
67
84
  // step 2. write to the log appender.
68
85
  this.writeToLog(this.config().level, message, this.tags);
@@ -71,7 +88,7 @@ export abstract class Log {
71
88
  console.log(e);
72
89
  }
73
90
  }
74
-
91
+
75
92
  protected abstract writeToLog(level:string, message:string, tags:{[key:string]:string|boolean|number}):void;
76
93
  }
77
94
 
@@ -110,6 +127,11 @@ export abstract class AbstractLogger<BaseLoggerConfig>{
110
127
  protected abstract createLogger(config: LoggerTemplateConfig):Log;
111
128
  }
112
129
 
130
+ @ServiceDescription({
131
+ id: "@theotherwillembotha/loggerservice",
132
+ sourceFile: "@theotherwillembotha/node-red-plugincore",
133
+ dependencies: [LoggerTemplate]
134
+ })
113
135
  export class LoggerService extends BaseService {
114
136
 
115
137
  public static instanceID:string;
@@ -123,7 +145,7 @@ export class LoggerService extends BaseService {
123
145
  this.red = red;
124
146
 
125
147
  return new Promise<void>((resolve) => {
126
- network.get_active_interface((err:any, obj:any) => {
148
+ getNetwork().get_active_interface((_err:any, obj:any) => {
127
149
  LoggerService.instanceID = obj.ip_address;
128
150
  });
129
151
  });
@@ -131,16 +153,6 @@ export class LoggerService extends BaseService {
131
153
 
132
154
  public deinit(red: NodeAPI<NodeAPISettingsWithData>): void | Promise<void> {}
133
155
 
134
- static override getServiceDescriptor():ServiceDescriptor {
135
- return new ServiceDescriptor(
136
- "@theotherwillembotha/loggerservice",
137
- "LoggerService",
138
- "services-plugin",
139
- "@theotherwillembotha/node-red-plugincore",
140
- LoggerService,
141
- [LoggerTemplate]
142
- );
143
- }
144
156
  }
145
157
 
146
158
  export type LoggerConfigNodeConfig = ConfigNodeConfig & BaseLoggerConfig & {}
@@ -160,10 +172,11 @@ export abstract class LoggerConfigNode<CNC extends LoggerConfigNodeConfig, Logge
160
172
 
161
173
  export class DoNothingAppender extends Log{
162
174
 
163
- private static instance:DoNothingAppender = new DoNothingAppender();
175
+ private static _instance: DoNothingAppender | null = null;
164
176
 
165
- static get(): any {
166
- return DoNothingAppender.instance;
177
+ static get(): DoNothingAppender {
178
+ if (!DoNothingAppender._instance) DoNothingAppender._instance = new DoNothingAppender();
179
+ return DoNothingAppender._instance;
167
180
  }
168
181
 
169
182
  private constructor(){
@@ -59,10 +59,10 @@
59
59
  .towb_editorlabel {
60
60
  width: 120px !important;
61
61
  }
62
- .towb_editorfield {
62
+ input.towb_editorfield, select.towb_editorfield, textarea.towb_editorfield {
63
63
  width: 70% !important;
64
64
  }
65
- .towb_editorfield_short {
65
+ input.towb_editorfield_short, select.towb_editorfield_short {
66
66
  width: 30% !important;
67
67
  }
68
68
 
@@ -108,13 +108,13 @@
108
108
  </script>
109
109
 
110
110
  <script type="text/javascript" template-section="onIncludeEditPrepare">
111
- let node = this;
112
-
113
111
  // controls.
114
112
  let logEnabled = $("#{{defaults.logEnabled}}");
115
113
  let logTemplateEnabled = $("#{{defaults.logTemplateOverrideEnabled}}");
116
114
  let logTemplateEnabledSection = $("#section_logTemplateOverrideEnabled");
117
115
  let logEnabledSection = $("#section_logEnabled");
116
+ let loggerSection = $("#section_loggerconfig");
117
+ loggerSection.hide();
118
118
 
119
119
  // functions.
120
120
  let getLoggerTypes = async function(){
@@ -262,10 +262,15 @@
262
262
  }
263
263
  });
264
264
 
265
- // lastly, make sure that we set the correct value on the logger selector.
266
- updateLoggerSelectorList().then(() => {
267
- loggerSelector.val(node.logger);
268
- loggerSelector.trigger('change');
265
+ // Show the logger section only if at least one logger type is registered.
266
+ // If nodered_logging (or any other logger provider) is not installed, the section stays hidden.
267
+ getLoggerTypes().then(loggerTypes => {
268
+ if (loggerTypes.length === 0) return;
269
+ loggerSection.show();
270
+ updateLoggerSelectorList().then(() => {
271
+ loggerSelector.val(node.logger);
272
+ loggerSelector.trigger('change');
273
+ });
269
274
  });
270
275
 
271
276
  </script>