@bkmj/node-red-contrib-odbcmj 2.0.1 → 2.0.3

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 (3) hide show
  1. package/odbc.html +16 -27
  2. package/odbc.js +25 -12
  3. package/package.json +1 -1
package/odbc.html CHANGED
@@ -31,15 +31,13 @@
31
31
  oneditprepare: function () {
32
32
  var node = this;
33
33
 
34
- // --- Logique pour les sections déroulantes ---
35
- // On ajoute un écouteur de clic sur les en-têtes de section
34
+ // Logique pour les sections déroulantes
36
35
  $('.form-section-header').on('click', function() {
37
36
  $(this).toggleClass('expanded');
38
- // On fait basculer le conteneur d'options qui suit immédiatement l'en-tête
39
37
  $(this).next('.form-section-content').slideToggle();
40
38
  });
41
39
 
42
- // --- Logique pour le mode de connexion hybride ---
40
+ // Logique pour le mode de connexion hybride
43
41
  function toggleConnectionMode(mode) {
44
42
  if (mode === 'structured') {
45
43
  $(".config-mode-structured").show();
@@ -65,7 +63,7 @@
65
63
  toggleDriverField($(this).val());
66
64
  }).trigger("change");
67
65
 
68
- // --- Logiques pour les cases à cocher ---
66
+ // Logiques pour les cases à cocher
69
67
  $("#node-config-input-syntaxtick").on("change", function () {
70
68
  $(".input-syntax").toggle(this.checked);
71
69
  }).trigger("change");
@@ -74,7 +72,7 @@
74
72
  $(".retry-options").toggle(this.checked);
75
73
  }).trigger("change");
76
74
 
77
- // --- Logique pour le bouton de test ---
75
+ // Logique pour le bouton de test
78
76
  $('#node-config-test-connection').on('click', function() {
79
77
  var button = $(this);
80
78
  var originalText = "Test Connection";
@@ -84,11 +82,6 @@
84
82
 
85
83
  var connectionMode = $("#node-config-input-connectionMode").val();
86
84
 
87
- // --- CORRECTION : Récupérer le bon mot de passe selon le mode ---
88
- var password = (connectionMode === 'structured')
89
- ? $("#node-config-input-password-structured").val()
90
- : $("#node-config-input-password-string").val();
91
-
92
85
  var configData = {
93
86
  connectionMode: connectionMode,
94
87
  dbType: $("#node-config-input-dbType").val(),
@@ -96,8 +89,9 @@
96
89
  server: $("#node-config-input-server").val(),
97
90
  database: $("#node-config-input-database").val(),
98
91
  user: $("#node-config-input-user").val(),
99
- password: password,
100
- connectionString: $("#node-config-input-connectionString").val()
92
+ connectionString: $("#node-config-input-connectionString").val(),
93
+ // Le mot de passe n'est envoyé que si on est en mode structuré
94
+ password: (connectionMode === 'structured') ? $("#node-config-input-password").val() : null
101
95
  };
102
96
 
103
97
  $.ajax({
@@ -128,6 +122,7 @@
128
122
  padding: 5px;
129
123
  border-bottom: 1px solid #ddd;
130
124
  margin-bottom: 10px;
125
+ user-select: none;
131
126
  }
132
127
  .form-section-header i.fa-caret-right {
133
128
  transition: transform 0.2s ease-in-out;
@@ -181,20 +176,15 @@
181
176
  <input type="text" id="node-config-input-user">
182
177
  </div>
183
178
  <div class="form-row">
184
- <label for="node-config-input-password-structured"><i class="fa fa-lock"></i> Password</label>
185
- <input type="password" id="node-config-input-password-structured">
179
+ <label for="node-config-input-password"><i class="fa fa-lock"></i> Password</label>
180
+ <input type="password" id="node-config-input-password">
186
181
  </div>
187
182
  </div>
188
183
 
189
184
  <div class="config-mode-string">
190
185
  <div class="form-row">
191
186
  <label for="node-config-input-connectionString"><i class="fa fa-font"></i> Connection String</label>
192
- <input type="text" id="node-config-input-connectionString" placeholder="DRIVER={...};PWD={{{password}}};">
193
- </div>
194
- <div class="form-row">
195
- <label for="node-config-input-password-string"><i class="fa fa-lock"></i> Password</label>
196
- <input type="password" id="node-config-input-password-string">
197
- <span class="form-tips">Use <code>{{{password}}}</code> placeholder in the string above.</span>
187
+ <input type="text" id="node-config-input-connectionString" placeholder="DRIVER={...};SERVER=...;UID=...;PWD=...;">
198
188
  </div>
199
189
  </div>
200
190
 
@@ -205,8 +195,8 @@
205
195
 
206
196
  <hr/>
207
197
 
208
- <div class="form-section-header expanded"><h4><i class="fa fa-caret-right"></i> <i class="fa fa-sitemap"></i> Pool Options</h4></div>
209
- <div class="form-section-content">
198
+ <div class="form-section-header"><h4><i class="fa fa-caret-right"></i> <i class="fa fa-sitemap"></i> Pool Options</h4></div>
199
+ <div class="form-section-content" style="display: none;">
210
200
  <div class="form-row">
211
201
  <label for="node-config-input-initialSize"><i class="fa fa-play"></i> Initial Size</label>
212
202
  <input type="number" id="node-config-input-initialSize" placeholder="5" />
@@ -235,8 +225,8 @@
235
225
  </div>
236
226
  </div>
237
227
 
238
- <div class="form-section-header expanded"><h4><i class="fa fa-caret-right"></i> <i class="fa fa-exclamation-triangle"></i> Error Handling & Retry</h4></div>
239
- <div class="form-section-content">
228
+ <div class="form-section-header"><h4><i class="fa fa-caret-right"></i> <i class="fa fa-exclamation-triangle"></i> Error Handling & Retry</h4></div>
229
+ <div class="form-section-content" style="display: none;">
240
230
  <div class="form-row">
241
231
  <label for="node-config-input-retryFreshConnection" style="width: auto;"><i class="fa fa-refresh"></i> Retry with fresh connection</label>
242
232
  <input type="checkbox" id="node-config-input-retryFreshConnection" style="display: inline-block; width: auto; vertical-align: top;" />
@@ -277,10 +267,9 @@
277
267
  </div>
278
268
  </script>
279
269
 
280
-
281
270
  <script type="text/javascript">
282
271
  RED.nodes.registerType("odbc", {
283
- category: "storage-input",
272
+ category: "storage",
284
273
  color: "#89A5C0",
285
274
  defaults: {
286
275
  name: { value: "" },
package/odbc.js CHANGED
@@ -120,14 +120,18 @@ module.exports = function (RED) {
120
120
  }
121
121
  });
122
122
 
123
+ // --- API ENDPOINT POUR LE BOUTON DE TEST (VERSION CORRIGÉE) ---
123
124
  RED.httpAdmin.post("/odbc_config/:id/test", RED.auth.needsPermission("odbc.write"), async function(req, res) {
124
125
  const tempConfig = req.body;
125
- const tempCredentials = { password: tempConfig.password };
126
- delete tempConfig.password;
127
126
 
127
+ // Cette fonction interne ne doit PAS interagir avec `res`.
128
+ // Elle retourne une chaîne ou lance une erreur.
128
129
  const buildTestConnectionString = () => {
129
- if (tempConfig.connectionMode === 'structured') {
130
- if (!tempConfig.dbType || !tempConfig.server) return res.status(400).send("Mode structuré : le type de BD et le serveur sont requis.");
130
+ if (tempConfig.connectionMode === 'structured') {
131
+ if (!tempConfig.dbType || !tempConfig.server) {
132
+ // On lance une erreur au lieu d'envoyer une réponse.
133
+ throw new Error("En mode structuré, le type de base de données et le serveur sont requis.");
134
+ }
131
135
  let driver;
132
136
  let parts = [];
133
137
  switch (tempConfig.dbType) {
@@ -137,15 +141,19 @@ module.exports = function (RED) {
137
141
  default: driver = tempConfig.driver || ''; break;
138
142
  }
139
143
  if(driver) parts.unshift(`DRIVER={${driver}}`);
140
- parts.push(`SERVER=${tempConfig.server}`);
144
+ if (tempConfig.server) parts.push(`SERVER=${tempConfig.server}`);
141
145
  if (tempConfig.database) parts.push(`DATABASE=${tempConfig.database}`);
142
146
  if (tempConfig.user) parts.push(`UID=${tempConfig.user}`);
143
- if (tempCredentials.password) parts.push(`PWD=${tempCredentials.password}`);
147
+ // Le mot de passe est géré dans le bloc try/catch principal
148
+ if (tempConfig.password) parts.push(`PWD=${tempConfig.password}`);
149
+
144
150
  return parts.join(';');
145
- } else {
151
+
152
+ } else { // 'string' mode
146
153
  let connStr = tempConfig.connectionString || "";
147
- if (tempCredentials.password && connStr.includes('{{{password}}}')) {
148
- connStr = connStr.replace('{{{password}}}', tempCredentials.password);
154
+ // Le mot de passe est supposé être dans la chaîne ici
155
+ if (!connStr) {
156
+ throw new Error("La chaîne de connexion ne peut pas être vide.");
149
157
  }
150
158
  return connStr;
151
159
  }
@@ -153,14 +161,19 @@ module.exports = function (RED) {
153
161
 
154
162
  let connection;
155
163
  try {
164
+ // Le bloc try/catch gère maintenant TOUTES les erreurs.
156
165
  const testConnectionString = buildTestConnectionString();
157
- if (!testConnectionString) return res.status(400).send("La chaîne de connexion est vide.");
166
+
158
167
  connection = await odbcModule.connect(testConnectionString);
159
- res.sendStatus(200);
168
+ res.sendStatus(200); // Succès, on envoie la seule et unique réponse.
169
+
160
170
  } catch (err) {
171
+ // Qu'il s'agisse d'une erreur de validation ou de connexion, on l'attrape ici.
161
172
  res.status(500).send(err.message || "Erreur inconnue durant le test.");
162
173
  } finally {
163
- if (connection) await connection.close();
174
+ if (connection) {
175
+ await connection.close();
176
+ }
164
177
  }
165
178
  });
166
179
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bkmj/node-red-contrib-odbcmj",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "A powerful Node-RED node to connect to any ODBC data source, with connection pooling, advanced retry logic, and result streaming.",
5
5
  "keywords": [
6
6
  "node-red",