diff --git a/.vscode/launch.json b/.vscode/launch.json index 8f3c51a..02d0c7e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -76,14 +76,14 @@ // "--file-type", // "excel", - // // "--file-name", - // // "testdata/tasks.xlsx", - // // "--sheet-name", - // // "Ctrl-Q task import 1", + // "--file-name", + // "testdata/tasks.xlsx", + // "--sheet-name", + // "Ctrl-Q task import 1", - // "--import-app", - // "--import-app-sheet-name", - // "App import", + // // "--import-app", + // // "--import-app-sheet-name", + // // "App import", // // "--qvf-overwrite", // // "no", @@ -91,8 +91,8 @@ // // "--limit-import-count", // // "2", - // "--sleep-app-upload", - // "500", + // // "--sleep-app-upload", + // // "500", // // "--dry-run" // ] @@ -187,82 +187,82 @@ // ------------------------------------ // Import apps from Excel file // ------------------------------------ - "args": [ - "app-import", - "--auth-type", - "cert", - "--host", - "192.168.100.109", - "--auth-cert-file", - "./cert/client.pem", - "--auth-cert-key-file", - "./cert/client_key.pem", - "--auth-user-dir", - "LAB", - "--auth-user-id", - "goran", - - // "--file-type", - // "excel", - - "--file-name", - "testdata/tasks.xlsx", - "--sheet-name", - "App-import", - - // "--limit-import-count", - // "2", - - "--sleep-app-upload", - "500" - - // "--dry-run" - ] - - // ------------------------------------ - // Get task tree - // ------------------------------------ // "args": [ - // "task-get", + // "app-import", // "--auth-type", // "cert", // "--host", // "192.168.100.109", - // // "--auth-cert-file", - // // "./cert/client.pem", - // // "--auth-cert-key-file", - // // "./cert/client_key.pem", + // "--auth-cert-file", + // "./cert/client.pem", + // "--auth-cert-key-file", + // "./cert/client_key.pem", // "--auth-user-dir", // "LAB", // "--auth-user-id", // "goran", - // // "--task-id", - // // "82bc3e66-c899-4e44-b52f-552145da5ee0", - // "--task-tag", - // "Test data", - // "--output-format", - // "table", - // // "tree", - // // "--tree-icons", - // // "--tree-details", - // // "taskid", - // // "appname", - // // "--task-type", - // // "reload", - // // "ext-program", - - // // "--output-dest", - // // "screen", - // // "file", - // // "--output-file-name", - // // "tasks.json", - // // "--output-file-format", - // // "json", - // // "--text-color", - // // "no", + // // "--file-type", + // // "excel", + + // "--file-name", + // "testdata/tasks.xlsx", + // "--sheet-name", + // "App-import", + + // // "--limit-import-count", + // // "2", + + // "--sleep-app-upload", + // "500" + + // // "--dry-run" // ] + // ------------------------------------ + // Get task tree + // ------------------------------------ + "args": [ + "task-get", + // "--auth-type", + // "cert", + "--host", + "192.168.100.109", + // "--auth-cert-file", + // "./cert/client.pem", + // "--auth-cert-key-file", + // "./cert/client_key.pem", + "--auth-user-dir", + "LAB", + "--auth-user-id", + "goran", + // "--task-id", + // "82bc3e66-c899-4e44-b52f-552145da5ee0", + // "--task-tag", + // "Test data", + // "--output-format", + // "table", + // "tree", + // "--tree-icons", + // "--tree-details", + // "taskid", + // "appname", + "--task-type", + "reload", + "ext-program", + + // "--output-dest", + // "screen", + // "file", + // "--output-file-name", + // "tasks.json", + // "--output-file-format", + // "json", + + // "--text-color", + // "no", + ] + // ------------------------------------ // Get reload tasks as table // ------------------------------------ diff --git a/src/lib/app/class_allapps.js b/src/lib/app/class_allapps.js index 2638fd9..4194378 100644 --- a/src/lib/app/class_allapps.js +++ b/src/lib/app/class_allapps.js @@ -36,7 +36,7 @@ class QlikSenseApps { logger.error(`QS APP: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`QS APP:\n ${err.stack}`); } } @@ -143,7 +143,7 @@ class QlikSenseApps { logger.error(`GET QS APP 2: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`GET QS APP 2:\n ${err.stack}`); } @@ -583,7 +583,7 @@ class QlikSenseApps { logger.error(`UPDATE UPLOADED APP: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`UPDATE UPLOADED APP:\n ${err.stack}`); } @@ -670,7 +670,7 @@ class QlikSenseApps { logger.error(`(${appCounter}) PUBLISH APP publish-replace: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`(${appCounter}) PUBLISH APP publish-replace:\n ${err.stack}`); } return { res: false, publishedApp: null }; @@ -702,7 +702,7 @@ class QlikSenseApps { logger.error(`(${appCounter}) PUBLISH APP publish-another: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`(${appCounter}) PUBLISH APP publish-another:\n ${err.stack}`); } @@ -771,7 +771,7 @@ class QlikSenseApps { logger.error(`(${appCounter}) PUBLISH APP delete-publish: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`(${appCounter}) PUBLISH APP delete-publish:\n ${err.stack}`); } @@ -813,7 +813,7 @@ class QlikSenseApps { logger.error(`PUBLISH APP NORMAL: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`PUBLISH APP NORMAL:\n ${err.stack}`); } @@ -853,7 +853,7 @@ class QlikSenseApps { logger.error(`PUBLISH APP REPLACE: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`PUBLISH APP REPLACE:\n ${err.stack}`); } @@ -909,7 +909,7 @@ class QlikSenseApps { logger.error(`CHECK IF APP EXISTS IN STREAM: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`CHECK IF APP EXISTS IN STREAM:\n ${err.stack}`); } @@ -959,7 +959,7 @@ class QlikSenseApps { logger.error(`GET APP IN STREAM: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`GET APP IN STREAM:\n ${err.stack}`); } @@ -1042,7 +1042,7 @@ class QlikSenseApps { logger.error(`CHECK IF STREAM EXISTS: Failed: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`CHECK IF STREAM EXISTS:\n ${err.stack}`); } @@ -1146,7 +1146,7 @@ class QlikSenseApps { logger.error(`CREATE RELOAD TASK IN QSEOW 2: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`CREATE RELOAD TASK IN QSEOW 2:\n ${err.stack}`); } @@ -1184,7 +1184,7 @@ class QlikSenseApps { logger.error(`[${err}] Export app step 1`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`[${err}] Export app step 1:\n ${err.stack}`); } diff --git a/src/lib/task/class_alltasks.js b/src/lib/task/class_alltasks.js index df9b61b..152976b 100644 --- a/src/lib/task/class_alltasks.js +++ b/src/lib/task/class_alltasks.js @@ -19,7 +19,7 @@ const { getTagIdByName } = require('../util/tag'); const { getCustomPropertyIdByName } = require('../util/customproperties'); const { taskExistById } = require('../util/task'); const { getAppById } = require('../util/app'); -const { getTaskByName } = require('../util/task'); +const { getTaskById, getTaskByName } = require('../util/task'); class QlikSenseTasks { // eslint-disable-next-line no-useless-constructor @@ -72,6 +72,11 @@ class QlikSenseTasks { this.taskList.push(newTask); } + // Function to read task definitions from disk file (CSV or Excel) + // Parameters: + // - tasksFromFile: Object containing data read from file + // - tagsExisting: Array of existing tags in QSEoW + // - cpExisting: Array of existing custom properties in QSEoW async getTaskModelFromFile(tasksFromFile, tagsExisting, cpExisting) { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { @@ -146,7 +151,7 @@ class QlikSenseTasks { let taskCreationOption; // Get task specific data for the current task - // The row containing task data will have a "Reload" in the task type column + // The row containing task data will have "Reload" in the task type column const taskData = taskRows.filter( (item) => item[taskFileColumnHeaders.taskType.pos] && @@ -612,7 +617,7 @@ class QlikSenseTasks { } else { // Verify task ID exists in QSEoW // eslint-disable-next-line no-await-in-loop - const taskExists = await this.getTaskById(currentTask.id); + const taskExists = await getTaskById(currentTask.id); if (!taskExists) { throw new Error( `Task "${currentTask.id}" does not exist in QSEoW and cannot be updated. ` + @@ -682,13 +687,13 @@ class QlikSenseTasks { resolve(this.taskList); } catch (err) { - if (err.response?.status) { + if (err?.response?.status) { logger.error(`Received error ${err.response?.status}/${err.response?.statusText} from QRS API`); } - if (err.response.data) { + if (err?.response?.data) { logger.error(`Error message from QRS API: ${err.response.data}`); } - if (err.config.data) { + if (err?.config?.data) { logger.error(`Data sent to Sense: ${JSON.stringify(JSON.parse(err.config.data), null, 2)}}`); } logger.error(`PARSE TASKS FROM FILE 1: ${err}`); @@ -869,7 +874,7 @@ class QlikSenseTasks { } async getTasksFromQseow() { - // eslint-disable-next-line no-async-promise-executor + // eslint-disable-next-line no-async-promise-executor, no-unused-vars return new Promise(async (resolve, reject) => { // try { logger.debug('GET TASK: Starting get reload tasks from QSEoW'); @@ -989,10 +994,6 @@ class QlikSenseTasks { } } resolve(this.taskList); - // } catch (err) { - // logger.error(`GET QS TASK 2: ${err}`); - // reject(err); - // } }); } @@ -1007,6 +1008,11 @@ class QlikSenseTasks { const newTreeLevel = parentTreeLevel + 1; let subTree = []; + // Debug + logger.debug( + `GET TASK SUBTREE: Meta node type: ${task.metaNodeType}, task type: ${task.taskType}, tree level: ${newTreeLevel}, task name: ${task.taskName}` + ); + // Does this node (=task) have any downstream connections? const downstreamTasks = self.taskNetwork.edges.filter((edge) => edge.from === task.id); @@ -1161,7 +1167,7 @@ class QlikSenseTasks { return subTree; // console.log('subTree: ' + JSON.stringify(subTree)); } catch (err) { - logger.error(`GET TASK SUBTREE: ${err.stack}`); + logger.error(`GET TASK SUBTREE (tree): ${err.stack}`); return false; } } @@ -1173,6 +1179,9 @@ class QlikSenseTasks { const newTreeLevel = parentTreeLevel + 1; let subTree = []; + // Debug + // logger.debug(`GET TASK SUBTABLE: Tree level: ${newTreeLevel}, task name: ${task.taskName}`); + // Does this node (=task) have any downstream connections? const downstreamTasks = self.taskNetwork.edges.filter((edge) => edge.from === task.id); // console.log('downStreamTasks 1: ' + JSON.stringify(downstreamTasks)); @@ -1232,7 +1241,7 @@ class QlikSenseTasks { return subTree; } catch (err) { - logger.error(`GET TASK SUBTREE: ${err}`); + logger.error(`GET TASK SUBTREE (table): ${err}`); return null; } } @@ -1270,6 +1279,8 @@ class QlikSenseTasks { try { logger.verbose(`Getting schema events from QSEoW...`); const result1 = await this.qlikSenseSchemaEvents.getSchemaEventsFromQseow(); + + logger.silly(`Schema events from QSEoW: ${JSON.stringify(result1, null, 2)}`); } catch (err) { logger.error(`GET TASK MODEL FROM QSEOW 2: ${err}`); return false; @@ -1279,6 +1290,8 @@ class QlikSenseTasks { try { logger.verbose(`Getting composite events from QSEoW...`); const result2 = await this.qlikSenseCompositeEvents.getCompositeEventsFromQseow(); + + logger.silly(`Composite events from QSEoW: ${JSON.stringify(result2, null, 2)}`); } catch (err) { logger.error(`GET TASK MODEL FROM QSEOW 3: ${err}`); return false; @@ -1546,8 +1559,8 @@ class QlikSenseTasks { }); // Keep a note that this node has associated events nodesWithEvents.add(compositeEvent.compositeEvent.compositeRules[0].reloadTask.id); - nodesWithEvents.add(compositeEvent.compositeEvent.reloadTask.id); - } else if (validate(compositeEvent.compositeEvent.compositeRules[0].externalProgramTask.id)) { + nodesWithEvents.add(compositeEvent.compositeEvent.externalProgramTask.id); + } else if (validate(compositeEvent.compositeEvent.compositeRules[0]?.externalProgramTask?.id)) { logger.verbose( `Composite event "${compositeEvent.compositeEvent.name}" has an external program task triggered by external program task with ID=${compositeEvent.compositeEvent.compositeRules[0].externalProgramTask.id}.` ); @@ -1570,7 +1583,7 @@ class QlikSenseTasks { // Keep a note that this node has associated events nodesWithEvents.add(compositeEvent.compositeEvent.compositeRules[0].externalProgramTask.id); - nodesWithEvents.add(compositeEvent.compositeEvent.reloadTask.id); + nodesWithEvents.add(compositeEvent.compositeEvent.externalProgramTask.id); } else { logger.warn(`Composite event "${compositeEvent.compositeEvent.name}" is triggered by an unsupported task type.`); } diff --git a/src/lib/util/app.js b/src/lib/util/app.js index ff0d64d..27d7bf3 100644 --- a/src/lib/util/app.js +++ b/src/lib/util/app.js @@ -142,7 +142,7 @@ async function getAppById(appId, optionsParam) { logger.error(`GET APP BY ID: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`GET APP BY ID:\n ${err.stack}`); } @@ -182,7 +182,7 @@ async function deleteAppById(appId) { logger.error(`DELETE APP: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`DELETE APP:\n ${err.stack}`); } diff --git a/src/lib/util/task.js b/src/lib/util/task.js index 3239af9..c431e4b 100644 --- a/src/lib/util/task.js +++ b/src/lib/util/task.js @@ -65,7 +65,7 @@ async function taskExistById(taskId, optionsParam) { logger.error(`TASK EXIST BY ID: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`TASK EXIST BY ID:\n ${err.stack}`); } @@ -121,7 +121,7 @@ async function getTaskByName(taskName, optionsParam) { logger.error(`GET TASK BY NAME: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`GET TASK BY NAME:\n ${err.stack}`); } @@ -186,7 +186,7 @@ async function getTaskById(taskId, optionsParam) { logger.error(`GET TASK BY ID: ${err}`); // Show stack trace if available - if (err.stack) { + if (err?.stack) { logger.error(`GET TASK BY ID:\n ${err.stack}`); }