node-red-contrib-uos-nats 0.1.6 → 0.1.8

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 CHANGED
@@ -31,15 +31,15 @@ Fields:
31
31
  - **Host / Port** – IP address of your controller (e.g. `192.168.10.100`) and the NATS port `49360`.
32
32
  - **Client Name** – used for the NATS inbox prefix (`_INBOX.<name>`).
33
33
  - **Client ID / Secret** – OAuth2 client credentials created in the Control Center.
34
- - **Scope** – usually `hub.variables.provide hub.variables.readwrite`.
34
+ - **Scope** – fixed to `hub.variables.provide hub.variables.readwrite hub.variables.readonly` so the nodes can register providers and query the REST metadata; it is not editable in the UI.
35
35
  - **Granted scopes** – click *Refresh* to query the token endpoint and show the scopes currently granted to that client.
36
36
 
37
37
  The config node automatically fetches tokens via Client Credentials flow and exposes helper endpoints so other nodes can list providers and variables. The token endpoint is derived from the configured host (`https://<host>/oauth2/token`), so there is no additional field to maintain.
38
38
 
39
39
  ## DataHub Input Node
40
40
 
41
- - Select the u-OS config node, then choose one of the discovered providers from the dropdown (the node queries `/datahub/v1/providers` for you).
42
- - Pick the variables you need from the multi-select list. Leave it empty to receive all variables from the provider.
41
+ - Select the u-OS config node, then choose one of the discovered providers from the dropdown (the node queries `/datahub/v1/providers` for you). If your OAuth client lacks read-only scope, the dropdown is disabled and you can type the provider ID manually.
42
+ - Pick the variables you need from the multi-select list. Leave it empty to receive all variables from the provider. (When manual provider input is used the list may stay empty, because it also requires the read-only permission.)
43
43
  - The node outputs messages with the structure:
44
44
  ```json
45
45
  {
@@ -68,7 +68,7 @@ The config node automatically fetches tokens via Client Credentials flow and exp
68
68
  ## Example Flow
69
69
 
70
70
  1. Drop a **u-OS Config** node, fill in host/port and OAuth credentials from the Control Center.
71
- 2. Add a **DataHub Input** node, select the config, enter the provider ID and optional comma-separated variable list. Connect the output to a Debug node.
71
+ 2. Add a **DataHub Input** node, select the config, choose the provider from the dropdown (or type the provider ID if the API access is restricted) and pick the variables you care about. Connect the output to a Debug node.
72
72
  3. Add a **DataHub Output** node, leave provider ID = `nodered` and send structured JSON (e.g. from a Function node). The values instantly appear in the Data Hub under the provider `nodered`.
73
73
 
74
74
  > Tip: Because both nodes rely on the Control Center HTTP API for metadata they inherit the same permissions as your OAuth client. Make sure the client has at least `hub.variables.readonly` for the input node and `hub.variables.provide hub.variables.readwrite` for the output node.
@@ -14,13 +14,15 @@
14
14
  oneditprepare: function() {
15
15
  const node = this;
16
16
  const $config = $('#node-input-connection');
17
- const $provider = $('#node-input-providerId');
17
+ const $providerHidden = $('#node-input-providerId');
18
+ const $providerSelect = $('#datahub-provider-select');
19
+ const $providerManual = $('#datahub-provider-manual');
18
20
  const $providerStatus = $('#datahub-provider-status');
19
21
  const $variablesHidden = $('#node-input-variablesText');
20
22
  const $variables = $('#datahub-input-variables');
21
23
  const $variablesStatus = $('#datahub-variables-status');
22
24
 
23
- const initialProvider = node.providerId;
25
+ const initialProvider = $providerHidden.val() || '';
24
26
  const initialVars = ($variablesHidden.val() || '')
25
27
  .split(',')
26
28
  .map((entry) => entry.trim())
@@ -68,6 +70,24 @@
68
70
  const setProviderStatus = (text) => $providerStatus.text(text || '');
69
71
  const setVariableStatus = (text) => $variablesStatus.text(text || '');
70
72
 
73
+ const setProviderValue = (value) => {
74
+ $providerHidden.val(value || '');
75
+ };
76
+
77
+ const getProviderValue = () => $providerHidden.val() || '';
78
+
79
+ const showManualProvider = (message) => {
80
+ $providerSelect.hide().prop('disabled', true);
81
+ $providerManual.show().prop('disabled', false);
82
+ $providerManual.val(getProviderValue());
83
+ setProviderStatus(message || 'Enter the provider ID manually.');
84
+ };
85
+
86
+ const showSelectProvider = () => {
87
+ $providerManual.hide().prop('disabled', true);
88
+ $providerSelect.show().prop('disabled', false);
89
+ };
90
+
71
91
  const loadVariables = (providerId, keepSelection = false) => {
72
92
  const configId = $config.val();
73
93
  if (!configId || !providerId) {
@@ -121,10 +141,10 @@
121
141
  const loadProviders = () => {
122
142
  const configId = $config.val();
123
143
  if (!configId) {
124
- $provider.empty();
125
- $provider.append('<option value="">Select a u-OS config first</option>');
126
- $provider.prop('disabled', true);
127
- setProviderStatus('Pick or create a u-OS config node before selecting a provider.');
144
+ $providerSelect.empty();
145
+ $providerSelect.append('<option value="">Select a u-OS config first</option>');
146
+ $providerSelect.prop('disabled', true);
147
+ showManualProvider('Pick or create a u-OS config node before selecting a provider.');
128
148
  setVariableStatus('');
129
149
  $variables.empty();
130
150
  $variables.prop('disabled', true);
@@ -132,18 +152,20 @@
132
152
  }
133
153
  const seq = ++providerRequest;
134
154
  setProviderStatus('Loading providers…');
135
- $provider.prop('disabled', true);
155
+ $providerSelect.prop('disabled', true);
156
+ showSelectProvider();
136
157
  $.getJSON(`uos/providers/${configId}`)
137
158
  .done((payload) => {
138
159
  if (seq !== providerRequest) {
139
160
  return;
140
161
  }
141
162
  const list = normalizeProviders(payload);
142
- $provider.empty();
163
+ $providerSelect.empty();
143
164
  if (!list.length) {
144
- $provider.append('<option value="">No providers available</option>');
165
+ $providerSelect.append('<option value="">No providers available</option>');
166
+ $providerSelect.prop('disabled', true);
145
167
  setProviderStatus('No providers returned. Verify Data Hub access.');
146
- $provider.prop('disabled', true);
168
+ showManualProvider('No providers returned. Enter the ID manually if you know it.');
147
169
  return;
148
170
  }
149
171
  list.forEach((prov) => {
@@ -154,24 +176,23 @@
154
176
  const option = $('<option></option>')
155
177
  .attr('value', value)
156
178
  .text(providerLabel(prov));
157
- $provider.append(option);
179
+ $providerSelect.append(option);
158
180
  });
159
- $provider.prop('disabled', false);
181
+ $providerSelect.prop('disabled', false);
160
182
  if (initialProvider) {
161
- $provider.val(initialProvider);
183
+ $providerSelect.val(initialProvider);
162
184
  }
163
- if (!$provider.val()) {
164
- $provider.val($provider.find('option:first').attr('value'));
185
+ if (!$providerSelect.val()) {
186
+ $providerSelect.val($providerSelect.find('option:first').attr('value'));
165
187
  }
188
+ const selected = $providerSelect.val();
189
+ setProviderValue(selected);
166
190
  setProviderStatus('Choose the provider you want to subscribe to.');
167
- loadVariables($provider.val());
191
+ loadVariables(selected);
168
192
  })
169
193
  .fail((xhr) => {
170
194
  const msg = xhr?.responseJSON?.error || xhr.statusText || 'Failed to load providers.';
171
- $provider.empty();
172
- $provider.append('<option value="">Unable to load providers</option>');
173
- $provider.prop('disabled', true);
174
- setProviderStatus(msg);
195
+ showManualProvider(`Provider list failed (${msg}). Enter the provider ID manually or grant hub.variables.readonly.`);
175
196
  });
176
197
  };
177
198
 
@@ -179,10 +200,22 @@
179
200
  syncVariablesField();
180
201
  });
181
202
 
182
- $provider.on('change', () => {
203
+ $providerSelect.on('change', () => {
204
+ const value = $providerSelect.val();
205
+ setProviderValue(value);
183
206
  $variablesHidden.val('');
184
207
  syncVariablesField();
185
- loadVariables($provider.val(), false);
208
+ loadVariables(value, false);
209
+ });
210
+
211
+ $providerManual.on('change keyup paste', () => {
212
+ const value = $providerManual.val();
213
+ setProviderValue(value);
214
+ $variablesHidden.val('');
215
+ syncVariablesField();
216
+ if (value) {
217
+ loadVariables(value, false);
218
+ }
186
219
  });
187
220
 
188
221
  $config.on('change', () => {
@@ -212,8 +245,12 @@
212
245
  <input type="text" id="node-input-connection">
213
246
  </div>
214
247
  <div class="form-row">
215
- <label for="node-input-providerId"><i class="fa fa-id-badge"></i> Provider</label>
216
- <select id="node-input-providerId"></select>
248
+ <label><i class="fa fa-id-badge"></i> Provider</label>
249
+ <div style="flex:1;">
250
+ <select id="datahub-provider-select" style="width:100%;"></select>
251
+ <input type="text" id="datahub-provider-manual" placeholder="provider id" style="width:100%; display:none;">
252
+ <input type="hidden" id="node-input-providerId">
253
+ </div>
217
254
  </div>
218
255
  <div class="form-row">
219
256
  <label></label>
@@ -1,11 +1,12 @@
1
1
  <script type="text/javascript">
2
+ const FIXED_SCOPE = 'hub.variables.provide hub.variables.readwrite hub.variables.readonly';
2
3
  RED.nodes.registerType('uos-config', {
3
4
  category: 'config',
4
5
  defaults: {
5
6
  host: { value: '127.0.0.1', required: true },
6
7
  port: { value: 49360, required: true, validate: RED.validators.number() },
7
8
  clientName: { value: 'nodered', required: true },
8
- scope: { value: 'hub.variables.provide hub.variables.readwrite', required: true },
9
+ scope: { value: FIXED_SCOPE, required: true },
9
10
  },
10
11
  credentials: {
11
12
  clientId: { type: 'text', required: true },
@@ -54,6 +55,9 @@
54
55
  evt.preventDefault();
55
56
  fetchScopes();
56
57
  });
58
+ $('#node-config-input-scope').val(FIXED_SCOPE);
59
+ $('#uos-scope-fixed').text(FIXED_SCOPE);
60
+
57
61
  if (node.credentials && node.credentials.clientId) {
58
62
  fetchScopes();
59
63
  }
@@ -82,9 +86,10 @@
82
86
  <label for="node-config-input-clientSecret"><i class="fa fa-key"></i> Client Secret</label>
83
87
  <input type="password" id="node-config-input-clientSecret">
84
88
  </div>
89
+ <input type="hidden" id="node-config-input-scope">
85
90
  <div class="form-row">
86
- <label for="node-config-input-scope"><i class="fa fa-list"></i> Scope</label>
87
- <input type="text" id="node-config-input-scope">
91
+ <label><i class="fa fa-list"></i> Scope</label>
92
+ <span id="uos-scope-fixed" class="form-tips"></span>
88
93
  </div>
89
94
  <div class="form-row">
90
95
  <label><i class="fa fa-info-circle"></i> Granted scopes</label>
@@ -102,7 +107,7 @@
102
107
  <li><strong>Host / Port</strong> – IP and NATS port of the controller (default <code>127.0.0.1:49360</code>).</li>
103
108
  <li><strong>Client Name</strong> – Friendly identifier used in NATS connection logs.</li>
104
109
  <li><strong>Client ID / Secret</strong> – OAuth credentials from your u-OS Control Center client.</li>
105
- <li><strong>Scope</strong> – Space separated scopes; e.g. <code>hub.variables.provide hub.variables.readwrite</code>.</li>
110
+ <li><strong>Scope</strong> – Fixed to <code>hub.variables.provide hub.variables.readwrite hub.variables.readonly</code> so the nodes can register providers and read metadata. It cannot be edited in the UI.</li>
106
111
  <li><strong>Granted scopes</strong> – Click <em>Refresh</em> to show what the token endpoint actually returns for this client.</li>
107
112
  </ul>
108
113
  </script>
@@ -1,5 +1,6 @@
1
1
  const fetch = require('node-fetch');
2
2
  const { connect } = require('nats');
3
+ const DEFAULT_SCOPE = 'hub.variables.provide hub.variables.readwrite hub.variables.readonly';
3
4
 
4
5
  if (!process.env.NODE_TLS_REJECT_UNAUTHORIZED) {
5
6
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
@@ -13,7 +14,7 @@ module.exports = function (RED) {
13
14
  this.host = config.host || '127.0.0.1';
14
15
  this.port = Number(config.port) || 49360;
15
16
  this.clientName = config.clientName || 'nodered';
16
- this.scope = config.scope || 'hub.variables.provide hub.variables.readwrite';
17
+ this.scope = DEFAULT_SCOPE;
17
18
  this.clientId = this.credentials.clientId;
18
19
  this.clientSecret = this.credentials.clientSecret;
19
20
  this.tokenInfo = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-uos-nats",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Node-RED nodes for u-OS Data Hub via NATS",
5
5
  "repository": {
6
6
  "type": "git",