profoundjs 6.1.0 → 6.3.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.
@@ -0,0 +1,17 @@
1
+
2
+ # Profound API Samples
3
+
4
+ A sample Profound API program. Server-side API logic is defined in low-code and JavaScript. A client-side program exists to demonstrate calling the API end point.
5
+
6
+ ## Sample GET, POST, PUT, DELETE, and Grid Request
7
+
8
+ Run the sample user interface by clicking either
9
+ * Launch > Launch App in Browser Tab
10
+ * Launch > Launch App in IDE
11
+
12
+ ## Files
13
+ * APISample.api.json - the server-side logic for the API endpoints, as Low Code steps
14
+ * APISample.js - program logic for the sample user interface to interact with the APIs
15
+ * APISample.json - sample user interface to interact with the APIs
16
+ * hobbyshop.csv - sample data file
17
+ * readCSVFile.js - sample module to handle reading and writing to the data file. Used in Low Code steps.
@@ -0,0 +1,6 @@
1
+ 1,Nintendo Switch,200,8
2
+ 2,AC Ambient,100 ,6
3
+ 3,XBOX one,120,3
4
+ 4,Sega Saturn,120,3
5
+ 5,Playstation 3,100,5
6
+ 6,bicycle gears,16,18
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+ /**
3
+ * A utility function to read a CSV file and output its contents in a pre-determined format.
4
+ */
5
+ const fs = require("fs"); // filestream module
6
+ const readline = require("readline"); // line-by-line reading module
7
+
8
+ /**
9
+ * Read a file line by line and output an object with its contents, with each field as properties of the object.
10
+ * @param {String} filename
11
+ * @param {Number} rowID
12
+ * @returns {Object}
13
+ */
14
+ async function fileRead(filename, rowID = 0) {
15
+ let fLength = 0;
16
+ const lData = [];
17
+ let lTemp = null;
18
+ // Start a file stream to read the file line-by-line
19
+ const fstream = fs.createReadStream(filename);
20
+ const linereader = readline.createInterface({
21
+ input: fstream,
22
+ crlfDelay: Infinity // used to identify all \r\n entries in the file as single line breaks
23
+ });
24
+
25
+ // Start reading the lines of the file
26
+ for await (const line of linereader) {
27
+ fLength++;
28
+ if (rowID == 0) { // read the whole file, parse each line into arrays
29
+ lTemp = line.split(",");
30
+ lData.push({ ID: lTemp[0], Name: lTemp[1], Price: lTemp[2], Quantity: lTemp[3] });
31
+ }
32
+ else if (fLength == rowID) {
33
+ lTemp = line.split(",");
34
+ lData.push({ ID: lTemp[0], Name: lTemp[1], Price: lTemp[2], Quantity: lTemp[3] });
35
+ }
36
+ };
37
+
38
+ return { length: fLength, data: lData };
39
+ }
40
+
41
+ /**
42
+ * Read a file line by line, changing the specified line, and then write the data back to the file.
43
+ * Return a message indicating which row was updated.
44
+ * The original file is changed.
45
+ * @param {String} filename
46
+ * @param {Number} rowID
47
+ * @returns {String}
48
+ */
49
+ async function fileUpdate(filename, rowID, data) {
50
+ let fLength = 0;
51
+ // Start a file stream to read the file line-by-line
52
+ const fstream = fs.createReadStream(filename);
53
+ const linereader = readline.createInterface({
54
+ input: fstream,
55
+ crlfDelay: Infinity // used to identify all \r\n entries in the file as single line breaks
56
+ });
57
+
58
+ let strUpdated = "";
59
+
60
+ // Start reading the lines of the file
61
+ for await (const line of linereader) {
62
+ fLength++;
63
+ if (fLength == rowID) {
64
+ strUpdated += fLength + "," + data + "\n"; // update the specific line if found
65
+ }
66
+ else strUpdated += line + "\n";
67
+ };
68
+ linereader.close();
69
+ fstream.close();
70
+
71
+ // remove the last entry of \n
72
+ strUpdated = strUpdated.substring(0, strUpdated.length - 1);
73
+
74
+ const message = await new Promise((resolve, reject) => {
75
+ // rewrite the file with the updated data
76
+ fs.writeFile(filename, strUpdated, (err) => {
77
+ if (err) reject(err);
78
+ else resolve("Row ID: " + iID + "\nData Updated: " + data);
79
+ });
80
+ });
81
+
82
+ return message;
83
+ }
84
+
85
+ /**
86
+ * Read a file line by line and build a string with the file contents, with the line specified by rowID removed.
87
+ * Write the new string to the file, overwriting the original file.
88
+ * Return a message indicating which row was deleted.
89
+ * @param {String} filename
90
+ * @param {Number} rowID
91
+ * @returns {String}
92
+ */
93
+ async function lineDelete(filename, rowID) {
94
+ let iCol = 0;
95
+ let fLength = 0;
96
+ let strUpdated = "";
97
+ let strTemp = "";
98
+ // Start a file stream to read the file line-by-line
99
+ const fstream = fs.createReadStream(filename);
100
+ const linereader = readline.createInterface({
101
+ input: fstream,
102
+ crlfDelay: Infinity // used to identify all \r\n entries in the file as single line breaks
103
+ });
104
+
105
+ // Start reading the lines of the file
106
+ for await (const line of linereader) {
107
+ fLength++;
108
+ if (fLength < rowID) { // Copy the line as is if it's not the row ID requested
109
+ strUpdated += line + "\n";
110
+ }
111
+ else if (fLength > rowID) { // Update the first column to reflect the correct line
112
+ iCol = line.indexOf(","); // find first occurence of , as the first column
113
+ strTemp = line.substring(iCol, line.length); // move the , and the data to temp string
114
+ strUpdated += (fLength - 1) + strTemp + "\n"; // add the line and its updated column number
115
+ }
116
+ };
117
+ linereader.close();
118
+ fstream.close();
119
+
120
+ // remove the last entry of \n
121
+ strUpdated = strUpdated.substring(0, strUpdated.length - 1);
122
+
123
+ // Write the strUpdated string to the file at filename:
124
+ const message = new Promise((resolve, reject) => {
125
+ fs.writeFile(filename, strUpdated, (err) => {
126
+ if (err) reject(err);
127
+ else resolve("Row " + rowID + " deleted.");
128
+ });
129
+ });
130
+
131
+ return message;
132
+ }
133
+
134
+ exports.fileRead = fileRead;
135
+ exports.fileUpdate = fileUpdate;
136
+ exports.lineDelete = lineDelete;
@@ -4,7 +4,7 @@
4
4
  {
5
5
  "screen": {
6
6
  "record format name": "signonscrn",
7
- "onload": "if(window.puiMobileClient == null){\n if(window.device != null){\n if(window.device.platform != null){\n if(window.device.platform == \"iOS\"){\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphics button\");\n applyProperty(\"SignOnButton\", \"width\", \"340px\");\n applyProperty(\"SignOnButton\", \"field type\", \"graphics button\");\n }\n } \n }\n}\npui.confirmOnClose = false;"
7
+ "onload": "if(window.puiMobileClient == null){\n if(window.device != null){\n if(window.device.platform != null){\n if(window.device.platform == \"iOS\"){\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphic button\");\n applyProperty(\"SignOnButton\", \"width\", \"340px\");\n applyProperty(\"SignOnButton\", \"field type\", \"graphic button\");\n }\n } \n }\n}\npui.confirmOnClose = false;"
8
8
  },
9
9
  "items": [
10
10
  {
@@ -166,7 +166,7 @@
166
166
  "screen": {
167
167
  "record format name": "errscrn",
168
168
  "disable enter key": "true",
169
- "onload": "\nif (pui[\"errorScreen\"] && pui[\"errorScreen\"][\"onload\"]) {\n pui[\"errorScreen\"][\"onload\"]();\n}\nelse {\n // Backwards compatibility code for when pui[\"errorScreen\"][\"onload\"]() is not available\n if ((window[\"puiMobileClient\"] == null && window[\"device\"] != null &&\n window[\"device\"][\"platform\"] == \"iOS\") ||\n pui.genie != null) {\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphics button\");\n }\n if (pui.genie != null) {\n applyProperty(\"NewSessionButton\", \"value\", pui.getLanguageText(\"runtimeText\", \"ok\"));\n applyProperty(\"NewSessionButton\", \"onclick\", \"pui.click();\");\n }\n pui.formatErrorText();\n pui.confirmOnClose = false;\n pui.shutdownOnClose = false;\n}\n"
169
+ "onload": "\nif (pui[\"errorScreen\"] && pui[\"errorScreen\"][\"onload\"]) {\n pui[\"errorScreen\"][\"onload\"]();\n}\nelse {\n // Backwards compatibility code for when pui[\"errorScreen\"][\"onload\"]() is not available\n if ((window[\"puiMobileClient\"] == null && window[\"device\"] != null &&\n window[\"device\"][\"platform\"] == \"iOS\") ||\n pui.genie != null) {\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphic button\");\n }\n if (pui.genie != null) {\n applyProperty(\"NewSessionButton\", \"value\", pui.getLanguageText(\"runtimeText\", \"ok\"));\n applyProperty(\"NewSessionButton\", \"onclick\", \"pui.click();\");\n }\n pui.formatErrorText();\n pui.confirmOnClose = false;\n pui.shutdownOnClose = false;\n}\n"
170
170
  },
171
171
  "items": [
172
172
  {
@@ -704,7 +704,7 @@
704
704
  {
705
705
  "screen": {
706
706
  "record format name": "eojscrn",
707
- "onload": "if(window.device != null){\n if(window.device.platform != null){\n if(window.device.platform == \"iOS\"){\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphics button\");\n applyProperty(\"NewSessionButton2\", \"width\", \"335px\");\n applyProperty(\"NewSessionButton2\", \"field type\", \"graphics button\");\n }\n }\n}\n\npui.endOfSession();"
707
+ "onload": "if(window.device != null){\n if(window.device.platform != null){\n if(window.device.platform == \"iOS\"){\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphic button\");\n applyProperty(\"NewSessionButton2\", \"width\", \"335px\");\n applyProperty(\"NewSessionButton2\", \"field type\", \"graphic button\");\n }\n }\n}\n\npui.endOfSession();"
708
708
  },
709
709
  "items": [
710
710
  {
@@ -774,7 +774,7 @@
774
774
  {
775
775
  "screen": {
776
776
  "record format name": "timoutscrn",
777
- "onload": "if(window.device != null){\n if(window.device.platform != null){\n if(window.device.platform == \"iOS\"){\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphics button\");\n applyProperty(\"NewSessionButton3\", \"width\", \"335px\");\n applyProperty(\"NewSessionButton3\", \"field type\", \"graphics button\");\n }\n }\n}\n\npui.endOfSession(\"Your session has timed out.\");"
777
+ "onload": "if(window.device != null){\n if(window.device.platform != null){\n if(window.device.platform == \"iOS\"){\n applyProperty(\"btnBack\", \"visibility\", \"hidden\");\n applyProperty(\"btnBack\", \"field type\", \"graphic button\");\n applyProperty(\"NewSessionButton3\", \"width\", \"335px\");\n applyProperty(\"NewSessionButton3\", \"field type\", \"graphic button\");\n }\n }\n}\n\npui.endOfSession(\"Your session has timed out.\");"
778
778
  },
779
779
  "items": [
780
780
  {
@@ -988,7 +988,8 @@
988
988
  "rjZeroFill": "false",
989
989
  "dataType": "varchar",
990
990
  "formatting": "Text",
991
- "textTransform": "none"
991
+ "textTransform": "none",
992
+ "designValue": "@media screen { #_id_ > .puiresp { display:grid; } }"
992
993
  },
993
994
  "use viewport": "true",
994
995
  "bottom": "0px",
Binary file
@@ -3,7 +3,7 @@
3
3
 
4
4
  /*
5
5
  Discovers and removes additional components that exist outside of the package installation directory.
6
-
6
+
7
7
  It's used by Profound Installer
8
8
 
9
9
  Any changes to the behavior may require changes to the "install_info.json" file or Profound Installer.
@@ -15,9 +15,8 @@ const readline = require("readline");
15
15
 
16
16
  const IBMi = iutils.isIBMi();
17
17
 
18
- (async () => {
18
+ (async() => {
19
19
  try {
20
-
21
20
  // Parse arguments.
22
21
  const argDefs = {
23
22
  alias: {
@@ -39,7 +38,7 @@ const IBMi = iutils.isIBMi();
39
38
 
40
39
  // Show help and quit, if requested.
41
40
  if (args["help"] === true) {
42
- const HELP = `Usage: node removeExtraComponents.js [OPTION]
41
+ const HELP = `Usage: node removeExtraComponents.js [OPTION]
43
42
  -h, --help Print this help and exit.
44
43
  -d, --dry-run Report what items would be removed, without removing them.
45
44
  -s, --silent Bypass confirmation prompt.
@@ -170,7 +169,6 @@ It is intended to be used before uninstalling the package via NPM.
170
169
  }
171
170
  console.log("Removal of extra components complete.");
172
171
  process.stdin.destroy();
173
-
174
172
  }
175
173
  catch (error) {
176
174
  process.stdin.destroy();
@@ -194,7 +192,7 @@ function exec(command, quiet = false) {
194
192
  const opts = {
195
193
  env: {
196
194
  QIBM_USE_DESCRIPTOR_STDIO: "Y",
197
- QIBM_MULTI_THREADED: "N",
195
+ QIBM_MULTI_THREADED: "N"
198
196
  },
199
197
  stdio: "pipe",
200
198
  windowsHide: true
package/setup/setup.js CHANGED
@@ -28,8 +28,8 @@ const uuidv4 = require("uuid").v4;
28
28
 
29
29
  const IBMi = iutils.isIBMi();
30
30
 
31
- let RED = "\x1b[31m";
32
- let CYAN = "\x1b[36m";
31
+ let RED = "\x1b[31m";
32
+ let CYAN = "\x1b[36m";
33
33
  let RESET = "\x1b[0m";
34
34
 
35
35
  const logDir = path.join(os.tmpdir(), "profoundjs-" + uuidv4());
@@ -38,9 +38,8 @@ let logFile;
38
38
 
39
39
  let SILENT_MODE = false;
40
40
 
41
- (async () => {
41
+ (async() => {
42
42
  try {
43
-
44
43
  // Parse arguments.
45
44
  const args = minimist(
46
45
  process.argv.slice(2),
@@ -73,7 +72,7 @@ let SILENT_MODE = false;
73
72
 
74
73
  // Show help and quit, if requested.
75
74
  if (args["help"]) {
76
- const HELP = `Usage: npm run setup -- [OPTION]
75
+ const HELP = `Usage: npm run setup -- [OPTION]
77
76
  -c, --config-file=<file> Alternate config file.
78
77
  -h, --help Print this help and exit.
79
78
  --nodegit Install nodegit.
@@ -289,6 +288,13 @@ let SILENT_MODE = false;
289
288
  log("Copying pjssamples.");
290
289
  copyDir(path.join(__dirname, "modules", "pjssamples"), path.join(deployDir, "modules"));
291
290
 
291
+ // Create PAPI samples directory
292
+ if (directoryExists(path.join(deployDir, "modules", "papisamples"))) {
293
+ fs.removeSync(path.join(deployDir, "modules", "papisamples"));
294
+ }
295
+ log("Copying papisamples.");
296
+ copyDir(path.join(__dirname, "modules", "papisamples"), path.join(deployDir, "modules"));
297
+
292
298
  // Create store_credentials.js.
293
299
  if (fileExists(path.join(deployDir, "store_credentials.js"))) {
294
300
  log("store_credentials.js file exists.");
@@ -307,6 +313,17 @@ let SILENT_MODE = false;
307
313
  log("store_options.js created.");
308
314
  }
309
315
 
316
+ // Begin OAuth2 requirements.
317
+ // Create encrypt_client_file.js.
318
+ if (fileExists(path.join(deployDir, "encrypt_client_file.js"))) {
319
+ log("encrypt_client_file.js file exists.");
320
+ }
321
+ else {
322
+ copyFile(path.join(__dirname, "encrypt_client_file.js"), deployDir, "utf8");
323
+ log("encrypt_client_file.js created.");
324
+ }
325
+ // End OAuth2 requirements.
326
+
310
327
  // Create call.js.
311
328
  if (fileExists(path.join(deployDir, "call.js"))) {
312
329
  log("call.js file exists.");
@@ -316,6 +333,10 @@ let SILENT_MODE = false;
316
333
  log("call.js created.");
317
334
  }
318
335
 
336
+ // Create lic_client.js
337
+ copyFile(path.join(__dirname, "lic_client.js"), deployDir, "utf8");
338
+ log("lic_client.js created.");
339
+
319
340
  // Convert start.js to Promises, if necessary.
320
341
  const convertStartJS = require("./convertStartJS.js");
321
342
  if (convertStartJS(path.join(deployDir, "start.js"))) {
@@ -326,7 +347,7 @@ let SILENT_MODE = false;
326
347
  if (IBMi) {
327
348
  log("");
328
349
  if (args["ibmi-connector-library"] || args["ibmi-instance"] !== undefined) {
329
- let portNumber = config.port || 8081;
350
+ const portNumber = config.port || 8081;
330
351
  let connectorLibrary = "*NONE";
331
352
  let connectorIASP;
332
353
  if (args["ibmi-connector-library"]) {
@@ -350,7 +371,7 @@ let SILENT_MODE = false;
350
371
  }
351
372
  }
352
373
  // First, try copying the save file
353
- var success = runCommand("CPYFRMSTMF FROMSTMF('" + __dirname + "/pjsdist.savf') TOMBR('/QSYS.LIB/QGPL.LIB/PJSDIST.FILE') MBROPT(*REPLACE)");
374
+ let success = runCommand("CPYFRMSTMF FROMSTMF('" + __dirname + "/pjsdist.savf') TOMBR('/QSYS.LIB/QGPL.LIB/PJSDIST.FILE') MBROPT(*REPLACE)");
354
375
  if (!success) {
355
376
  logError("Unable to create installer save file.");
356
377
  die();
@@ -366,13 +387,15 @@ let SILENT_MODE = false;
366
387
  die();
367
388
  }
368
389
  // Now, try running PJSINSTALL
369
- var command = "QGPL/PJSINSTALL CONNLIB(" + connectorLibrary + ")";
370
- if (connectorLibrary != "*NONE")
390
+ let command = "QGPL/PJSINSTALL CONNLIB(" + connectorLibrary + ")";
391
+ if (connectorLibrary != "*NONE") {
371
392
  command += " CONNIASP(" + connectorIASP + ") CONNHOST('localhost') CONNPORT(" + portNumber + ")";
393
+ }
372
394
  command += " SVRNAME(" + svrname + ")";
373
- if (svrname != "*NONE")
395
+ if (svrname != "*NONE") {
374
396
  command += " SVRDIR('" + deployDir + "') " +
375
397
  "SVRAUTO(" + ((autostart) ? "*YES" : "*NO") + ") CCSID(" + ccsid + ") NODEPATH('" + nodePath + "')";
398
+ }
376
399
  success = runCommand(command, "-Ke");
377
400
  // Clean up program and save file
378
401
  log("");
@@ -402,7 +425,6 @@ let SILENT_MODE = false;
402
425
  }
403
426
  }
404
427
  log(`\n${CYAN}Profound.js installation complete.${RESET}\n`);
405
-
406
428
  }
407
429
  catch (error) {
408
430
  logError(error);
@@ -424,7 +446,7 @@ function logToFile(...args) {
424
446
  if (SILENT_MODE) {
425
447
  return;
426
448
  }
427
- let output = `${util.format(...args)}\n`; // Mimic console.log().
449
+ let output = `${util.format(...args)}\n`; // Mimic console.log().
428
450
  output = output.replace(/\x1b\[[0-9]+m/g, ""); // Strip terminal escape codes for colors.
429
451
  fs.writeFileSync(logFile, output, { flag: "a" });
430
452
  }
@@ -442,7 +464,7 @@ function copyDir(dir, destinationDir) {
442
464
  fs.mkdirSync(path.join(destinationDir, dirName));
443
465
  const files = fs.readdirSync(dir);
444
466
  files.forEach(function(file, index) {
445
- if(fs.lstatSync(path.join(dir, file)).isDirectory()) { // recurse
467
+ if (fs.lstatSync(path.join(dir, file)).isDirectory()) { // recurse
446
468
  copyDir(path.join(dir, file), path.join(destinationDir, dirName));
447
469
  }
448
470
  else {
@@ -453,18 +475,22 @@ function copyDir(dir, destinationDir) {
453
475
 
454
476
  function copyFile(file, destination, type) {
455
477
  if (type == null) type = "binary";
456
- if (directoryExists(destination))
457
- var toFile = path.join(destination, path.basename(file));
458
- else
459
- var toFile = destination;
460
- var content = fs.readFileSync(file, type);
478
+ let toFile;
479
+ if (directoryExists(destination)) {
480
+ toFile = path.join(destination, path.basename(file));
481
+ }
482
+ else {
483
+ toFile = destination;
484
+ }
485
+ const content = fs.readFileSync(file, type);
461
486
  fs.writeFileSync(toFile, content, type);
462
487
  }
463
488
 
464
489
  function createPuiscreens(deployDir) {
465
- function copyFileOldVersionIs(version, compareStr){
490
+ const targetPuiScreensFile = path.join(deployDir, "modules", "puiscreens.json");
491
+ function copyFileOldVersionIs(version, compareStr) {
466
492
  compareStr = compareStr || "=";
467
- log("Found Standard puiscreens.json file version "+compareStr+" "+version+", replacing with current version...");
493
+ log("Found Standard puiscreens.json file version " + compareStr + " " + version + ", replacing with current version...");
468
494
  copyFile(path.join(__dirname, "modules", "puiscreens.json"), targetPuiScreensFile, "utf8");
469
495
  log("puiscreens.json file was replaced.");
470
496
  }
@@ -477,11 +503,15 @@ function createPuiscreens(deployDir) {
477
503
  // 3. If it's not an official version, check if we have lower case User & Password. If not, then backup existing version to puiscreens_bak.json and install this official version.
478
504
  // 4. Otherwise it's not an official version but should work OK. So leave existing puiscreens.json, and check if we already have a puiscreens_orig.json, and
479
505
  // create it if not.
480
- var targetPuiScreensFile = path.join(deployDir, "modules", "puiscreens.json");
481
506
  if (fileExists(targetPuiScreensFile)) {
482
-
483
- var data = fs.readFileSync(targetPuiScreensFile);
484
- var checksum = crypto.createHash("sha512").update(data).digest("hex"); // sha512 best for 64-bit
507
+ const data = fs.readFileSync(targetPuiScreensFile);
508
+ const checksum = crypto.createHash("sha512").update(data).digest("hex"); // sha512 best for 64-bit
509
+ let format = null;
510
+ let puiScreens;
511
+ let goodUser = false;
512
+ let goodPassword = false;
513
+ let goodSubmit = false;
514
+ let goodError = false;
485
515
 
486
516
  switch (checksum) {
487
517
  case "4fb38daa851aacd21cf3aeaa92304df4e0353cae2b6dab3a5fd53c0cf4d42875b5efadbb4bb29642cbff07bfdd8e1c7a9c107f582905f7fc798c3841e888ee61":
@@ -531,39 +561,38 @@ function createPuiscreens(deployDir) {
531
561
 
532
562
  case "3aaab88d4cf922f01a09bab3424ecf81460c7679a6d51ecb0f187fdce97e627499128e9b8c46d83075098e7e8f7150b73936056b1accedff55a79c69d65cb20b":
533
563
  // Note: Betas were considered pre-release versions. 6.0.0 is the release version; so 6.0.0 is newer than 6.0.0-beta.X
534
- log("Found Standard puiscreens.json file version >= 6.0.0, no need for update.");
564
+ copyFileOldVersionIs("6.0.0");
565
+ break;
566
+
567
+ case "41a350ae45c7616fe1824fb236b48ab64ca6d0de1023946e16ef9de4eea804649ff13123fa4ce630bb93308c8312f75e12448bbe58e91802dc8b12cc27bfd051":
568
+ log("Found Standard puiscreens.json file version > 6.0.0, no need for update.");
535
569
  break;
536
570
 
537
571
  default:
538
- var puiScreens = JSON.parse(data);
572
+ puiScreens = JSON.parse(data);
539
573
  log("Found Customized puiscreens.json file, analyzing contents...");
540
574
 
541
575
  // We need to check the signon screen and make sure we have lower case bound fields
542
- var goodUser = false, goodPassword = false, goodSubmit = false, goodError = false;
543
-
544
- formats:
545
- for (var i in puiScreens.formats) {
546
- var format = puiScreens.formats[i];
547
-
548
- if (format.screen["record format name"].toLowerCase() === "signonscrn") {
549
- for (var j in format.items) {
550
- var itemValue = format.items[j].value;
551
- if (itemValue && typeof itemValue === "object") {
552
- if (itemValue.fieldName === "ssuser") goodUser = true;
553
- else if (itemValue.fieldName === "sspassword") goodPassword = true;
554
- }
555
- var itemResponse = format.items[j].response;
556
- if (itemResponse && typeof itemResponse === "object") {
557
- if (itemResponse.fieldName === "sssubmit") goodSubmit = true;
558
- }
559
- var itemHtml = format.items[j].html;
560
- if (itemHtml && typeof itemHtml === "object") {
561
- if (itemHtml.fieldName === "sserror") goodError = true;
562
- }
563
-
564
- if (goodUser && goodPassword && goodSubmit && goodError) break formats;
576
+ if (Array.isArray(puiScreens.formats)) {
577
+ format = puiScreens.formats.find(format => typeof format.screen["record format name"] === "string" && format.screen["record format name"].toLowerCase() === "signonscrn");
578
+ }
579
+ if (format) {
580
+ for (const j in format.items) {
581
+ const itemValue = format.items[j].value;
582
+ if (itemValue && typeof itemValue === "object") {
583
+ if (itemValue.fieldName === "ssuser") goodUser = true;
584
+ else if (itemValue.fieldName === "sspassword") goodPassword = true;
565
585
  }
566
- break;
586
+ const itemResponse = format.items[j].response;
587
+ if (itemResponse && typeof itemResponse === "object") {
588
+ if (itemResponse.fieldName === "sssubmit") goodSubmit = true;
589
+ }
590
+ const itemHtml = format.items[j].html;
591
+ if (itemHtml && typeof itemHtml === "object") {
592
+ if (itemHtml.fieldName === "sserror") goodError = true;
593
+ }
594
+
595
+ if (goodUser && goodPassword && goodSubmit && goodError) break;
567
596
  }
568
597
  }
569
598
 
@@ -588,9 +617,9 @@ function createPuiscreens(deployDir) {
588
617
  }
589
618
 
590
619
  function directoryExists(dir) {
591
- var exists = false;
620
+ let exists = false;
592
621
  try {
593
- var stat = fs.statSync(dir);
622
+ const stat = fs.statSync(dir);
594
623
  if (stat && stat.isDirectory()) exists = true;
595
624
  }
596
625
  catch (err) {
@@ -600,9 +629,9 @@ function directoryExists(dir) {
600
629
  }
601
630
 
602
631
  function fileExists(file) {
603
- var exists = false;
632
+ let exists = false;
604
633
  try {
605
- var stat = fs.statSync(file);
634
+ const stat = fs.statSync(file);
606
635
  if (stat && stat.isFile()) exists = true;
607
636
  }
608
637
  catch (err) {
@@ -612,9 +641,8 @@ function fileExists(file) {
612
641
  }
613
642
 
614
643
  function runCommand(command, switches) {
615
-
616
644
  log("Executing IBM i command: " + command);
617
- var args = [command];
645
+ const args = [command];
618
646
  if (typeof switches == "string") {
619
647
  args.unshift(switches);
620
648
  }
@@ -632,7 +660,8 @@ function runCommand(command, switches) {
632
660
  env: {
633
661
  QIBM_USE_DESCRIPTOR_STDIO: "Y",
634
662
  QIBM_MULTI_THREADED: "N" // Many IBM commands cannot run in multi-threaded mode...
635
- }};
663
+ }
664
+ };
636
665
 
637
666
  const results = child_process.spawnSync("system", args, options);
638
667
 
@@ -648,8 +677,7 @@ function runCommand(command, switches) {
648
677
  }
649
678
  else {
650
679
  logError("Process ended due to signal %s", signal);
651
- logError(results); // show full results including detailed error
680
+ logError(results); // show full results including detailed error
652
681
  }
653
682
  return false;
654
-
655
683
  }
package/views/cloud.css CHANGED
@@ -258,10 +258,23 @@
258
258
  letter-spacing: .25px;
259
259
  }
260
260
 
261
- #_cloud_signin_button {
261
+ #_cloud_signin_button, #_cloud_signin_button_right {
262
262
  margin-top: 15px;
263
- width: 100%;
264
- display:block;
263
+ }
264
+
265
+ @media (max-width: 575px) {
266
+ #_cloud_signin_button, #_cloud_signin_button_right {
267
+ width: 100%;
268
+ display:block;
269
+ }
270
+ }
271
+ @media (min-width: 576px) {
272
+ #_cloud_signin_button, #_cloud_signin_button_right {
273
+ width: 47%;
274
+ }
275
+ #_cloud_signin_button_right {
276
+ float: right;
277
+ }
265
278
  }
266
279
 
267
280
  /*--- select template ---*/
@@ -602,9 +615,9 @@ span.pui-fa-brands-icons.fa-google {
602
615
  }
603
616
 
604
617
  ._cloud_signin_col {
605
- float: left;
606
- width: 50%;
607
- margin: auto;
618
+ /* float: left; */
619
+ /* width: 50%; */
620
+ /* margin: auto; */
608
621
  padding: 0 40px;
609
622
  margin-top: 6px;
610
623
  box-sizing: border-box;
package/views/key.ejs CHANGED
@@ -107,6 +107,21 @@
107
107
  color: white;
108
108
  }
109
109
 
110
+ .pjs-key-page .floating-lic-info {
111
+ color: white;
112
+ font-size: 15px;
113
+ width: 100%;
114
+ padding: 10px 30px 10px 60px;
115
+ }
116
+
117
+ .pjs-key-page .floating-lic-info div.pl-uuid span {
118
+ letter-spacing: 1.0px;
119
+ }
120
+
121
+ .pjs-key-page .floating-lic-info div.fl-lic-verif span.fl-lic-verif-dta.warning {
122
+ color: #FF3F00;
123
+ }
124
+
110
125
  .pjs-key-page .system-info {
111
126
  padding-left: 30px;
112
127
  padding-right: 30px;
@@ -353,6 +368,21 @@
353
368
  </div>
354
369
  <h1>License Key Management</h1>
355
370
  </div>
371
+ <% if (typeof floating !== "undefined"){ %>
372
+ <div class="floating-lic-info">
373
+ <div class="pl-uuid"><span>Floating License UUID: </span><%= floating.uuid %></div>
374
+ <div class="fl-lic-verif"><span class="fl-lic-verif-lbl">Verified: </span>
375
+ <% if (floating.verified) { %>
376
+ <span class="fl-lic-verif-dta">yes</span>
377
+ <% } else { %>
378
+ <span class="fl-lic-verif-dta warning">no - <%= floating.verified_msg %></span>
379
+ <% } %>
380
+ </div>
381
+ <div class="pulse-ts-exp">
382
+ <span>Machine heartbeat pulse required by (UTC): </span><%= floating.pulse_exp %>
383
+ </div>
384
+ </div>
385
+ <% } %>
356
386
  <div class="system-info">
357
387
  <div>
358
388
  <div class="machine-id"><span class="machine-id-label">Machine ID: </span>
@@ -408,7 +438,7 @@
408
438
  <form method="post" action="/key">
409
439
  <input type="hidden" name="apply" value="1" />
410
440
  <div class="paste-key">
411
- <textarea placeholder="Paste License Key Here" id="keyData" name="keyData" required></textarea>
441
+ <textarea placeholder="Paste License Key or Floating License Authorization Code Here" id="keyData" name="keyData" required></textarea>
412
442
  </div>
413
443
  <div class="apply-key">
414
444
  <input type="submit" value="Apply Key" />
@@ -422,7 +452,7 @@
422
452
  <label for="keyFile" />Or <span class="key-file-search">
423
453
  <div class="key-file-search-div">Browse</div>
424
454
  <input type="file" id="keyFile" name="keyFile" required onchange="displayKeyFileName(this);" />
425
- </span> to select a <a href="https://docs.profoundlogic.com/x/_wLrAw">Key File</a></label>
455
+ </span> to select a <a href="https://docs.profoundlogic.com/x/_wLrAw">Key or Floating License Authorization Code File</a></label>
426
456
  </div>
427
457
  <div class="key-file">
428
458
  <input class="key-file-to-upload" id="keyFileName" placeholder="Nothing to upload yet..." disabled="disabled" />