From 2bf47a56fcaeae598608cb0a5e046c35dffe67e2 Mon Sep 17 00:00:00 2001
From: John Sparger <john.sparger@ess.eu>
Date: Thu, 7 Apr 2022 11:56:46 +0000
Subject: [PATCH] Ui for showing alert links ICSHWI 9163

---
 cypress/fixtures/AwxJobDetails.json           |   6 +
 cypress/fixtures/IOCDetails.json              |  31 +-
 cypress/fixtures/ccce-api.json                | 966 ++++++++++--------
 src/api/SwaggerApi.js                         |   4 +-
 src/components/IOC/AlertMessages.js           |  25 +-
 src/components/IOC/IOCDetailFetcher.js        |  10 +-
 src/components/IOC/IOCLiveStatus.js           |  21 +-
 src/components/IOC/IOCLiveStatus.spec.js      |   8 +
 .../deployments/DeploymentDetailFetcher.js    |  10 +-
 .../deployments/DeploymentJobOutput.js        |  50 +-
 10 files changed, 623 insertions(+), 508 deletions(-)

diff --git a/cypress/fixtures/AwxJobDetails.json b/cypress/fixtures/AwxJobDetails.json
index 9dfa6382..cfbd5602 100644
--- a/cypress/fixtures/AwxJobDetails.json
+++ b/cypress/fixtures/AwxJobDetails.json
@@ -22,5 +22,11 @@
     "status": "successful",
     "started": "2022-03-29T13:00:52.023+00:00",
     "finished": "2022-03-29T13:02:18.225+00:00"
+  },
+  {
+    "id": 4544,
+    "status": "successful",
+    "started": "2022-04-06T07:33:50.410+00:00",
+    "finished": "2022-04-06T07:35:20.736+00:00"
   }
 ]
\ No newline at end of file
diff --git a/cypress/fixtures/IOCDetails.json b/cypress/fixtures/IOCDetails.json
index 6d1496b7..4e3dd774 100644
--- a/cypress/fixtures/IOCDetails.json
+++ b/cypress/fixtures/IOCDetails.json
@@ -11,16 +11,7 @@
     "sourceVersion": "0.0.1",
     "sourceVersionShort": "0.0.1",
     "activeDeployment": null,
-    "alerts": [
-      {
-        "type": "ERROR",
-        "message": "IOC's latest deployment failed, IOC may be in inconsistent state"
-      },
-      {
-        "type": "ERROR",
-        "message": "Prometheus exporters cannot be found (IOC and host details cannot be acquired)"
-      }
-    ],
+    "alerts": [],
     "operationInProgress": false,
     "active": null
   },
@@ -36,28 +27,38 @@
     "sourceVersion": "ee3ae2a8b9e7e83e4eb511eee340716e9d541056",
     "sourceVersionShort": "ee3ae2a8",
     "activeDeployment": {
-      "id": 38,
+      "id": 58,
       "createdBy": "johnsparger",
-      "startDate": "2022-03-29T13:00:52.023+00:00",
+      "startDate": "2022-04-06T07:33:50.410+00:00",
       "undeployment": false,
       "namingName": "CCCE:SC-IOC-001",
       "gitProjectId": 4801,
       "sourceVersion": "ee3ae2a8b9e7e83e4eb511eee340716e9d541056",
-      "endDate": "2022-03-29T13:02:18.225+00:00",
+      "endDate": "2022-04-06T07:35:20.736+00:00",
       "comment": "",
       "iocName": "CCCE:SC-IOC-001",
       "host": {
         "csEntryId": 4195,
+        "csEntryIdValid": true,
         "fqdn": "ccce-w40.cslab.esss.lu.se",
         "hostName": "ccce-w40",
         "network": "CSLab-GeneralLab"
       },
       "status": "JOB",
-      "awxJobId": 4382,
+      "awxJobId": 4544,
       "sourceUrl": "https://gitlab.esss.lu.se/ccce/dev/iocs/ccce-demo-w38.git",
       "sourceVersionShort": "ee3ae2a8"
     },
-    "alerts": [],
+    "alerts": [    {
+      "type": "ERROR",
+      "message": "Example alert without link"
+    },
+    {
+      "type": "ERROR",
+      "message": "Example alert with link",
+      "link": "https://google.com"
+    }
+  ],
     "operationInProgress": false,
     "active": true
   }
diff --git a/cypress/fixtures/ccce-api.json b/cypress/fixtures/ccce-api.json
index b3aa8ff0..2f804e42 100644
--- a/cypress/fixtures/ccce-api.json
+++ b/cypress/fixtures/ccce-api.json
@@ -64,18 +64,18 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Ioc not found",
+          "200": {
+            "description": "Found IOC",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/IocDetails"
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -84,18 +84,18 @@
               }
             }
           },
-          "200": {
-            "description": "Found IOC",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/IocDetails"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "404": {
+            "description": "Ioc not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -135,8 +135,8 @@
           "required": true
         },
         "responses": {
-          "422": {
-            "description": "Unprocessable request",
+          "403": {
+            "description": "Forbidden: User doesn't have the necessary permissions",
             "content": {
               "application/json": {
                 "schema": {
@@ -145,28 +145,28 @@
               }
             }
           },
-          "200": {
-            "description": "IOC updated",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/Ioc"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "404": {
-            "description": "Ioc not found",
+          "200": {
+            "description": "IOC updated",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/Ioc"
                 }
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "409": {
+            "description": "IOC already created or concurrent deployment, undeployment, start or stop for IOC is ongoing",
             "content": {
               "application/json": {
                 "schema": {
@@ -175,8 +175,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -185,8 +185,8 @@
               }
             }
           },
-          "409": {
-            "description": "IOC already created or concurrent deployment, undeployment, start or stop for IOC is ongoing",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -195,8 +195,8 @@
               }
             }
           },
-          "403": {
-            "description": "Forbidden: User doesn't have the necessary permissions",
+          "404": {
+            "description": "Ioc not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -205,8 +205,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "422": {
+            "description": "Unprocessable request",
             "content": {
               "application/json": {
                 "schema": {
@@ -241,8 +241,8 @@
           }
         ],
         "responses": {
-          "409": {
-            "description": "Concurrent deployment, undeployment, start or stop for IOC is ongoing",
+          "403": {
+            "description": "Forbidden: User doesn't have the necessary permissions",
             "content": {
               "application/json": {
                 "schema": {
@@ -261,8 +261,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "409": {
+            "description": "Concurrent deployment, undeployment, start or stop for IOC is ongoing",
             "content": {
               "application/json": {
                 "schema": {
@@ -271,18 +271,18 @@
               }
             }
           },
-          "204": {
-            "description": "IOC deleted",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "string"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "403": {
-            "description": "Forbidden: User doesn't have the necessary permissions",
+          "404": {
+            "description": "IOC not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -291,18 +291,18 @@
               }
             }
           },
-          "404": {
-            "description": "IOC not found",
+          "204": {
+            "description": "IOC deleted",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "string"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -350,8 +350,8 @@
               }
             }
           },
-          "404": {
-            "description": "Not found",
+          "409": {
+            "description": "Ongoing deployment, or undeployment for IOC",
             "content": {
               "application/json": {
                 "schema": {
@@ -360,8 +360,8 @@
               }
             }
           },
-          "422": {
-            "description": "IOC is not deployed",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -370,18 +370,21 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "Undeployment created",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Deployment"
+                  }
                 }
               }
             }
           },
-          "409": {
-            "description": "Ongoing deployment, or undeployment for IOC",
+          "404": {
+            "description": "Not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -390,21 +393,18 @@
               }
             }
           },
-          "200": {
-            "description": "Undeployment created",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/Deployment"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "422": {
+            "description": "IOC is not deployed",
             "content": {
               "application/json": {
                 "schema": {
@@ -439,8 +439,8 @@
           "required": true
         },
         "responses": {
-          "200": {
-            "description": "Job updated",
+          "404": {
+            "description": "Job not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -449,8 +449,8 @@
               }
             }
           },
-          "404": {
-            "description": "Job not found",
+          "200": {
+            "description": "Job updated",
             "content": {
               "application/json": {
                 "schema": {
@@ -459,8 +459,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -469,8 +469,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -569,8 +569,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -579,8 +579,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -608,28 +608,28 @@
           "required": true
         },
         "responses": {
-          "422": {
-            "description": "Unprocessable request",
+          "201": {
+            "description": "IOC created",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/Ioc"
                 }
               }
             }
           },
-          "201": {
-            "description": "IOC created",
+          "409": {
+            "description": "IOC already created",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/Ioc"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "400": {
-            "description": "Incomplete request",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -638,8 +638,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "400": {
+            "description": "Incomplete request",
             "content": {
               "application/json": {
                 "schema": {
@@ -648,8 +648,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "403": {
+            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
             "content": {
               "application/json": {
                 "schema": {
@@ -658,8 +658,8 @@
               }
             }
           },
-          "409": {
-            "description": "IOC already created",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -668,8 +668,8 @@
               }
             }
           },
-          "424": {
-            "description": "Metadata file not found, or not processable",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -678,8 +678,8 @@
               }
             }
           },
-          "403": {
-            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
+          "424": {
+            "description": "Metadata file not found, or not processable",
             "content": {
               "application/json": {
                 "schema": {
@@ -688,8 +688,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "422": {
+            "description": "Unprocessable request",
             "content": {
               "application/json": {
                 "schema": {
@@ -736,18 +736,18 @@
           "required": true
         },
         "responses": {
-          "422": {
-            "description": "CSEntry host not found",
+          "201": {
+            "description": "Deployment created",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/Deployment"
                 }
               }
             }
           },
-          "400": {
-            "description": "Incomplete request",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -766,8 +766,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "400": {
+            "description": "Incomplete request",
             "content": {
               "application/json": {
                 "schema": {
@@ -776,18 +776,18 @@
               }
             }
           },
-          "201": {
-            "description": "Deployment created",
+          "403": {
+            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/Deployment"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "422": {
+            "description": "CSEntry host not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -796,8 +796,8 @@
               }
             }
           },
-          "424": {
-            "description": "Metadata file not found, or not processable",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -806,8 +806,8 @@
               }
             }
           },
-          "403": {
-            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
+          "404": {
+            "description": "IOC not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -816,8 +816,8 @@
               }
             }
           },
-          "404": {
-            "description": "IOC not found",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -826,8 +826,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "424": {
+            "description": "Metadata file not found, or not processable",
             "content": {
               "application/json": {
                 "schema": {
@@ -864,8 +864,8 @@
           }
         ],
         "responses": {
-          "409": {
-            "description": "Concurrent deployment, undeployment, start or stop for IOC is ongoing",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -874,8 +874,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "409": {
+            "description": "Concurrent deployment, undeployment, start or stop for IOC is ongoing",
             "content": {
               "application/json": {
                 "schema": {
@@ -894,8 +894,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "403": {
+            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
             "content": {
               "application/json": {
                 "schema": {
@@ -914,8 +914,8 @@
               }
             }
           },
-          "403": {
-            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -934,8 +934,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -972,12 +972,12 @@
           }
         ],
         "responses": {
-          "201": {
-            "description": "IOC start initiated",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/AdHocCommand"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -992,8 +992,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "403": {
+            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
             "content": {
               "application/json": {
                 "schema": {
@@ -1002,8 +1002,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "422": {
+            "description": "IOC has no active deployment",
             "content": {
               "application/json": {
                 "schema": {
@@ -1012,8 +1012,8 @@
               }
             }
           },
-          "422": {
-            "description": "IOC has no active deployment",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -1022,8 +1022,8 @@
               }
             }
           },
-          "403": {
-            "description": "Forbidden: User doesn't have the necessary permissions in Gitlab",
+          "404": {
+            "description": "IOC not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -1032,8 +1032,8 @@
               }
             }
           },
-          "404": {
-            "description": "IOC not found",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -1042,12 +1042,12 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "201": {
+            "description": "IOC start initiated",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/AdHocCommand"
                 }
               }
             }
@@ -1090,21 +1090,18 @@
           "required": true
         },
         "responses": {
-          "201": {
-            "description": "Undeployment created",
+          "403": {
+            "description": "Forbidden: user doesn't have the necessary permissions in Gitlab",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/Deployment"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "409": {
-            "description": "Concurrent deployment, undeployment, start or stop for IOC is ongoing",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -1113,8 +1110,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "409": {
+            "description": "Concurrent deployment, undeployment, start or stop for IOC is ongoing",
             "content": {
               "application/json": {
                 "schema": {
@@ -1123,8 +1120,8 @@
               }
             }
           },
-          "404": {
-            "description": "Not found",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -1133,8 +1130,8 @@
               }
             }
           },
-          "422": {
-            "description": "IOC is not deployed",
+          "404": {
+            "description": "Not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -1143,18 +1140,21 @@
               }
             }
           },
-          "403": {
-            "description": "Forbidden: user doesn't have the necessary permissions in Gitlab",
+          "201": {
+            "description": "Undeployment created",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/Deployment"
+                  }
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "422": {
+            "description": "IOC is not deployed correctly",
             "content": {
               "application/json": {
                 "schema": {
@@ -1163,8 +1163,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -1318,8 +1318,8 @@
         "summary": "Own IOCs' statistics",
         "operationId": "personalStatistics",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -1328,22 +1328,22 @@
               }
             }
           },
-          "200": {
-            "description": "Personal statistics",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PersonalStatisticsResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "Personal statistics",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/PersonalStatisticsResponse"
                 }
               }
             }
@@ -1364,28 +1364,28 @@
         "summary": "Set of statistics",
         "operationId": "generalStatistics",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "Statistics about IOCs, deployments, and hosts",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/GeneralStatisticsResponse"
                 }
               }
             }
           },
-          "200": {
-            "description": "Statistics about IOCs, deployments, and hosts",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralStatisticsResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -1405,16 +1405,6 @@
         "summary": "IOC statistics",
         "operationId": "iocStatistics",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
-                }
-              }
-            }
-          },
           "200": {
             "description": "Statistics about IOCs deployed to hosts",
             "content": {
@@ -1437,6 +1427,16 @@
                 }
               }
             }
+          },
+          "401": {
+            "description": "Unauthorized",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
           }
         }
       }
@@ -1449,8 +1449,8 @@
         "summary": "Deployment statistics",
         "operationId": "deploymentStatistics",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -1472,8 +1472,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -1493,12 +1493,15 @@
         "summary": "Deployed IOC history from DB for statistics",
         "operationId": "iocDeploymentHistory",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "History about deployed IOCs from DB for statistics",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/ActiveIOCSForHistoryResponse"
+                  }
                 }
               }
             }
@@ -1513,15 +1516,12 @@
               }
             }
           },
-          "200": {
-            "description": "History about deployed IOCs from DB for statistics",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/ActiveIOCSForHistoryResponse"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -1537,6 +1537,16 @@
         "summary": "Currently active IOC statistics",
         "operationId": "currentlyActiveIocs",
         "responses": {
+          "500": {
+            "description": "Service exception",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
+          },
           "401": {
             "description": "Unauthorized",
             "content": {
@@ -1559,16 +1569,6 @@
                 }
               }
             }
-          },
-          "500": {
-            "description": "Service exception",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
-                }
-              }
-            }
           }
         }
       }
@@ -1581,16 +1581,6 @@
         "summary": "Active IOC history from Prometheus for statistics",
         "operationId": "activeIocHistory",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
-                }
-              }
-            }
-          },
           "200": {
             "description": "History about active IOCs for statistics",
             "content": {
@@ -1613,6 +1603,16 @@
                 }
               }
             }
+          },
+          "401": {
+            "description": "Unauthorized",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
           }
         }
       }
@@ -1636,18 +1636,21 @@
           }
         ],
         "responses": {
-          "503": {
-            "description": "Remote service unreachable",
+          "200": {
+            "description": "Naming names, and IDs from CCDB",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/NameResponse"
+                  }
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "503": {
+            "description": "Remote service unreachable",
             "content": {
               "application/json": {
                 "schema": {
@@ -1656,15 +1659,12 @@
               }
             }
           },
-          "200": {
-            "description": "Naming names, and IDs from CCDB",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/NameResponse"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -1716,8 +1716,8 @@
           }
         ],
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "503": {
+            "description": "Logging server unavailable",
             "content": {
               "application/json": {
                 "schema": {
@@ -1726,22 +1726,22 @@
               }
             }
           },
-          "503": {
-            "description": "Logging server unavailable",
+          "200": {
+            "description": "Log lines",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/LokiResponse"
                 }
               }
             }
           },
-          "200": {
-            "description": "Log lines",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/LokiResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -1854,8 +1854,8 @@
           }
         ],
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "503": {
+            "description": "Logging server unavailable",
             "content": {
               "application/json": {
                 "schema": {
@@ -1864,22 +1864,22 @@
               }
             }
           },
-          "503": {
-            "description": "Logging server unavailable",
+          "200": {
+            "description": "Log lines",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/LokiResponse"
                 }
               }
             }
           },
-          "200": {
-            "description": "Log lines",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/LokiResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -1910,6 +1910,16 @@
         "summary": "List own IOCs with alarms",
         "operationId": "listOwnIocsWithAlarms",
         "responses": {
+          "500": {
+            "description": "Service exception",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
+          },
           "401": {
             "description": "Unauthorized",
             "content": {
@@ -1932,16 +1942,6 @@
                 }
               }
             }
-          },
-          "500": {
-            "description": "Service exception",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
-                }
-              }
-            }
           }
         }
       }
@@ -1995,8 +1995,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote server exception",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2015,8 +2015,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "503": {
+            "description": "Remote server exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2068,12 +2068,12 @@
           }
         ],
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "Found Host",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/PagedAssociatedIocs"
                 }
               }
             }
@@ -2088,12 +2088,12 @@
               }
             }
           },
-          "200": {
-            "description": "Found Host",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PagedAssociatedIocs"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -2131,8 +2131,8 @@
               }
             }
           },
-          "404": {
-            "description": "Not found",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2141,8 +2141,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote server exception",
+          "404": {
+            "description": "Not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2161,8 +2161,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "503": {
+            "description": "Remote server exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2194,8 +2194,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Not found",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2204,8 +2204,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "404": {
+            "description": "Not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2214,22 +2214,22 @@
               }
             }
           },
-          "200": {
-            "description": "Found Host",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/TargetHost"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "Found Host",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/TargetHost"
                 }
               }
             }
@@ -2245,18 +2245,18 @@
         "summary": "Current-user information",
         "operationId": "userInfo",
         "responses": {
-          "503": {
-            "description": "Git exception",
+          "200": {
+            "description": "Information about the current user",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/UserInfoResponse"
                 }
               }
             }
           },
-          "404": {
-            "description": "Not found",
+          "503": {
+            "description": "Git exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2265,8 +2265,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2275,18 +2275,18 @@
               }
             }
           },
-          "200": {
-            "description": "Information about the current user",
+          "404": {
+            "description": "Not found",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/UserInfoResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -2322,31 +2322,31 @@
           }
         ],
         "responses": {
-          "503": {
-            "description": "Git exception",
+          "200": {
+            "description": "Information about the current user",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/UserInfoResponse"
+                  }
                 }
               }
             }
           },
-          "200": {
-            "description": "Information about the current user",
+          "503": {
+            "description": "Git exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/UserInfoResponse"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "404": {
-            "description": "Not found",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2355,8 +2355,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "404": {
+            "description": "Not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2365,8 +2365,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -2412,6 +2412,19 @@
           }
         ],
         "responses": {
+          "200": {
+            "description": "List of Tags and CommitIds for a specific GitLab repo",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/GitReference"
+                  }
+                }
+              }
+            }
+          },
           "503": {
             "description": "Git exception",
             "content": {
@@ -2422,6 +2435,58 @@
               }
             }
           },
+          "500": {
+            "description": "Service exception",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
+          },
+          "401": {
+            "description": "Unauthorized",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
+          }
+        }
+      }
+    },
+    "/api/v1/gitHelper/searchTagsAndCommitsByRef": {
+      "get": {
+        "tags": [
+          "Git"
+        ],
+        "summary": "Searches Tags and Commits by reference",
+        "operationId": "searchTagsAndCommitsByRefName",
+        "parameters": [
+          {
+            "name": "projectId",
+            "in": "query",
+            "description": "Git repo project ID",
+            "required": true,
+            "schema": {
+              "type": "integer",
+              "format": "int64"
+            }
+          },
+          {
+            "name": "reference",
+            "in": "query",
+            "description": "Git short reference",
+            "required": false,
+            "schema": {
+              "type": "string"
+            }
+          }
+        ],
+        "responses": {
           "200": {
             "description": "List of Tags and CommitIds for a specific GitLab repo",
             "content": {
@@ -2435,8 +2500,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "503": {
+            "description": "Git exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2454,8 +2519,23 @@
                 }
               }
             }
+          },
+          "401": {
+            "description": "Unauthorized",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
           }
-        }
+        },
+        "security": [
+          {
+            "bearerAuth": []
+          }
+        ]
       }
     },
     "/api/v1/gitHelper/projects": {
@@ -2466,18 +2546,21 @@
         "summary": "List IOC projects",
         "operationId": "listProjects",
         "responses": {
-          "503": {
-            "description": "Git exception",
+          "200": {
+            "description": "List of Gitlab projects of allowed groups",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "$ref": "#/components/schemas/GitProject"
+                  }
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "503": {
+            "description": "Git exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2496,15 +2579,12 @@
               }
             }
           },
-          "200": {
-            "description": "List of Gitlab projects of allowed groups",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "$ref": "#/components/schemas/GitProject"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -2629,28 +2709,28 @@
           }
         ],
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "A paged array of deployments",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/PagedDeploymentResponse"
                 }
               }
             }
           },
-          "200": {
-            "description": "A paged array of deployments",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PagedDeploymentResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -2682,18 +2762,18 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Deployment not found",
+          "200": {
+            "description": "A deployment with details",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/DeploymentInfoDetails"
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2702,18 +2782,18 @@
               }
             }
           },
-          "200": {
-            "description": "A deployment with details",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/DeploymentInfoDetails"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "404": {
+            "description": "Deployment not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2745,8 +2825,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Deployment not found",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2755,18 +2835,18 @@
               }
             }
           },
-          "200": {
-            "description": "AWX job details",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/AwxJobDetails"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -2775,8 +2855,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "404": {
+            "description": "Deployment not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2785,12 +2865,12 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "AWX job details",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/AwxJobDetails"
                 }
               }
             }
@@ -2818,8 +2898,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Deployment not found",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2828,8 +2908,8 @@
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2858,8 +2938,8 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "404": {
+            "description": "Deployment not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2926,8 +3006,8 @@
           }
         ],
         "responses": {
-          "404": {
-            "description": "Deployment not found",
+          "503": {
+            "description": "Remote service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -2936,18 +3016,18 @@
               }
             }
           },
-          "200": {
-            "description": "A command with details",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/PagedCommandResponse"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "503": {
-            "description": "Remote service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -2956,8 +3036,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "404": {
+            "description": "Deployment not found",
             "content": {
               "application/json": {
                 "schema": {
@@ -2966,12 +3046,12 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "A command with details",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/PagedCommandResponse"
                 }
               }
             }
@@ -3009,8 +3089,8 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -3019,22 +3099,22 @@
               }
             }
           },
-          "200": {
-            "description": "A command descriptor",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/AdHocCommand"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "A command descriptor",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/AdHocCommand"
                 }
               }
             }
@@ -3072,18 +3152,18 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "Ongoing command (if exists)",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/AdHocCommand"
                 }
               }
             }
           },
-          "404": {
-            "description": "IOC not found",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -3092,18 +3172,18 @@
               }
             }
           },
-          "200": {
-            "description": "Ongoing command (if exists)",
+          "404": {
+            "description": "IOC not found",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/AdHocCommand"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -3145,18 +3225,18 @@
               }
             }
           },
-          "200": {
-            "description": "A command with details",
+          "404": {
+            "description": "AWX command not found",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/AwxCommandDetails"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -3165,8 +3245,8 @@
               }
             }
           },
-          "404": {
-            "description": "AWX command not found",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
@@ -3175,12 +3255,12 @@
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "A command with details",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/AwxCommandDetails"
                 }
               }
             }
@@ -3196,22 +3276,22 @@
         "summary": "Get announcements",
         "operationId": "fetchAnnouncements",
         "responses": {
-          "401": {
-            "description": "Unauthorized",
+          "200": {
+            "description": "Announcements text",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "$ref": "#/components/schemas/Announcements"
                 }
               }
             }
           },
-          "200": {
-            "description": "Announcements text",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/Announcements"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
@@ -3249,18 +3329,21 @@
               }
             }
           },
-          "404": {
-            "description": "Role not found by authorization service",
+          "200": {
+            "description": "Ok",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "array",
+                  "items": {
+                    "type": "string"
+                  }
                 }
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -3269,21 +3352,18 @@
               }
             }
           },
-          "200": {
-            "description": "Ok",
+          "401": {
+            "description": "Unauthorized",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "array",
-                  "items": {
-                    "type": "string"
-                  }
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "404": {
+            "description": "Role not found by authorization service",
             "content": {
               "application/json": {
                 "schema": {
@@ -3319,16 +3399,6 @@
               }
             }
           },
-          "401": {
-            "description": "Unauthorized",
-            "content": {
-              "application/json": {
-                "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
-                }
-              }
-            }
-          },
           "200": {
             "description": "Ok",
             "content": {
@@ -3351,6 +3421,16 @@
                 }
               }
             }
+          },
+          "401": {
+            "description": "Unauthorized",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "$ref": "#/components/schemas/GeneralException"
+                }
+              }
+            }
           }
         },
         "security": [
@@ -3379,8 +3459,8 @@
               }
             }
           },
-          "403": {
-            "description": "Logout error",
+          "500": {
+            "description": "Service exception",
             "content": {
               "application/json": {
                 "schema": {
@@ -3389,22 +3469,22 @@
               }
             }
           },
-          "200": {
-            "description": "Ok",
+          "403": {
+            "description": "Logout error",
             "content": {
               "application/json": {
                 "schema": {
-                  "type": "object"
+                  "$ref": "#/components/schemas/GeneralException"
                 }
               }
             }
           },
-          "500": {
-            "description": "Service exception",
+          "200": {
+            "description": "Ok",
             "content": {
               "application/json": {
                 "schema": {
-                  "$ref": "#/components/schemas/GeneralException"
+                  "type": "object"
                 }
               }
             }
@@ -3459,6 +3539,9 @@
           },
           "message": {
             "type": "string"
+          },
+          "link": {
+            "type": "string"
           }
         }
       },
@@ -3505,6 +3588,7 @@
           "status": {
             "type": "string",
             "enum": [
+              "PENDING",
               "JOB",
               "QUEUED",
               "ERROR"
@@ -3529,6 +3613,9 @@
             "type": "integer",
             "format": "int64"
           },
+          "csEntryIdValid": {
+            "type": "boolean"
+          },
           "fqdn": {
             "type": "string"
           },
@@ -4325,6 +4412,13 @@
           },
           "shortReference": {
             "type": "string"
+          },
+          "description": {
+            "type": "string"
+          },
+          "commitDate": {
+            "type": "string",
+            "format": "date-time"
           }
         }
       },
@@ -4439,6 +4533,7 @@
           "status": {
             "type": "string",
             "enum": [
+              "PENDING",
               "JOB",
               "QUEUED",
               "ERROR"
@@ -4470,6 +4565,9 @@
             "type": "integer",
             "format": "int64"
           },
+          "csEntryIdValid": {
+            "type": "boolean"
+          },
           "fqdn": {
             "type": "string"
           }
diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js
index 0d2b68cc..bfe99e72 100644
--- a/src/api/SwaggerApi.js
+++ b/src/api/SwaggerApi.js
@@ -468,10 +468,10 @@ export function useHost(id) {
   return useAsync({ fcn: boundMethod});
 }
 
-export function useCSentryHost() {
+export function useCSentryHost(onError) {
   const api = useContext(apiContext);
   const method = useCallAndUnpack((id) => api.apis.Hosts.findCSentryHostById({hostCSEntryId: id}), unpackHost)
-  return useAsync({ fcn: method, call: false });
+  return useAsync({ fcn: method, call: false, onError: onError });
 }
 
 export function useAvailableHost(id) {
diff --git a/src/components/IOC/AlertMessages.js b/src/components/IOC/AlertMessages.js
index 8a9b1882..2589a428 100644
--- a/src/components/IOC/AlertMessages.js
+++ b/src/components/IOC/AlertMessages.js
@@ -1,14 +1,23 @@
 import React from 'react';
-import { Grid } from "@material-ui/core";
+import { Button, Grid } from "@material-ui/core";
 import { Alert } from "@material-ui/lab";
 
-export default function AlertMessages({alerts}) {
+export default function AlertMessages({ alerts }) {
   return (
-    <Grid container spacing={1}>
-    {(alerts.map((alert) => (
-      <Grid item xs={12} key={alert}>
-        <Alert severity={alert.type === "ERROR" ? "error" : "warning"}>{alert.message}</Alert>
-      </Grid>
-    )))}
+    <Grid id="ioc-alerts" container spacing={1}>
+      {(alerts.map((alert) => (
+        <Grid item xs={12} key={alert}>
+          <Alert
+            severity={alert.type === "ERROR" ? "error" : "warning"}
+            action={ alert.link &&
+              <Button target="_blank" href={alert.link} color="inherit" size="small">
+                More Info
+              </Button>
+            }
+          >
+            {alert.message}
+          </Alert>
+        </Grid>
+      )))}
     </Grid>)
 }
\ No newline at end of file
diff --git a/src/components/IOC/IOCDetailFetcher.js b/src/components/IOC/IOCDetailFetcher.js
index 7ad6b157..7d3477d5 100644
--- a/src/components/IOC/IOCDetailFetcher.js
+++ b/src/components/IOC/IOCDetailFetcher.js
@@ -1,13 +1,13 @@
 import { useEffect } from "react";
 import { useTagsAndCommitIds, useCSentryHost, useIocStatus } from "../../api/SwaggerApi";
 
-export function IOCDetailFetcher({ ioc, index, setIocs }) {
-  function onError(message) {
-    console.log(message);
-  }
+function onError(message) {
+  console.warn(message);
+}
 
+export function IOCDetailFetcher({ ioc, index, setIocs }) {
   const [tagOrCommitId, getTagOrCommitId] = useTagsAndCommitIds(onError);
-  const [host, getHost] = useCSentryHost();
+  const [host, getHost] = useCSentryHost(onError);
   const [iocStatus, getIocStatus] = useIocStatus();
 
   useEffect(() => {
diff --git a/src/components/IOC/IOCLiveStatus.js b/src/components/IOC/IOCLiveStatus.js
index 69de63df..1ba7aa0f 100644
--- a/src/components/IOC/IOCLiveStatus.js
+++ b/src/components/IOC/IOCLiveStatus.js
@@ -4,7 +4,6 @@ import { SimpleAccordion } from "../common/Accordion/SimpleAccordion";
 import { IOCDetails } from "./IOCDetails";
 import { Link } from 'react-router-dom';
 import { LokiContainer } from "../common/Loki/LokiContainer";
-import { Alert } from '@material-ui/lab';
 import GitRefLink from "./GitRefLink";
 import AlertMessages from "./AlertMessages";
 import { IOCService } from "./IOCService";
@@ -22,7 +21,7 @@ export function IOCLiveStatus({ ioc, currentCommand, commands, getCommands, butt
     if (ioc.activeDeployment?.awxJobId) {
       getDeploymentJobById(ioc.activeDeployment?.awxJobId);
     }
-  }, [getDeploymentJobById, ioc.activeDeployment?.awxJobId]) 
+  }, [getDeploymentJobById, ioc.activeDeployment?.awxJobId])
 
   const liveIOC = { ...ioc };
   liveIOC.name = ioc.namingName;
@@ -46,7 +45,7 @@ export function IOCLiveStatus({ ioc, currentCommand, commands, getCommands, butt
     }
     if (user) {
       subset["IOC Service Controls"] = showControls ?
-        <IOCService {...{ioc, currentCommand, getCommands, buttonDisabled, setButtonDisabled, commandColumnSort, commandLazyParams}} /> 
+        <IOCService {...{ ioc, currentCommand, getCommands, buttonDisabled, setButtonDisabled, commandColumnSort, commandLazyParams }} />
         : "Can't be controlled, because IOC is not (yet) deployed succesfully";
     }
 
@@ -65,16 +64,14 @@ export function IOCLiveStatus({ ioc, currentCommand, commands, getCommands, butt
           commandLazyParams={commandLazyParams} setCommandLazyParams={setCommandLazyParams} commandColumnSort={commandColumnSort} setCommandColumnSort={setCommandColumnSort}
           rowsPerPage={rowsPerPage} />
       </SimpleAccordion>
-      <AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
-        renderNoAccess={() => <></>}>
-        <SimpleAccordion summary="ProcServLog info" expaned={liveIOC.activeDeployment}>
-          {liveIOC.activeDeployment && (liveIOC.activeDeployment.host.csEntryId ?
+      {(liveIOC.activeDeployment?.host?.csEntryIdValid) &&
+        <AccessControl allowedRoles={["DeploymentToolAdmin", "DeploymentToolIntegrator"]}
+          renderNoAccess={() => <></>}>
+          <SimpleAccordion summary="ProcServLog info" defaultExpanded>
             <LokiContainer csEntryId={liveIOC.activeDeployment?.host.csEntryId} iocName={ioc.namingName} isDeployed={isIocDeployed(ioc)} />
-            :
-            <Alert severity="error" variant="standard">Invalid CSentry ID for target host</Alert>)
-          }
-        </SimpleAccordion>
-      </AccessControl>
+          </SimpleAccordion>
+        </AccessControl>
+      }
     </>
   );
 }
diff --git a/src/components/IOC/IOCLiveStatus.spec.js b/src/components/IOC/IOCLiveStatus.spec.js
index 8b8fb947..058b48f7 100644
--- a/src/components/IOC/IOCLiveStatus.spec.js
+++ b/src/components/IOC/IOCLiveStatus.spec.js
@@ -53,6 +53,14 @@ function commonTests() {
   cy.contains("IOC Service Control log").click()
   cy.get('.ccce-custom-table svg[title="Successful"]')
   cy.get('.ccce-custom-table svg[title="Start IOC"]')
+
+  // Expect alerts to be displayed
+  cy.get("#ioc-alerts")
+    .should("contain", "Example alert without link")
+    .and("contain", "Example alert with link")
+   
+  cy.get('#ioc-alerts a[href="https://google.com"]')
+    .contains("More Info", { matchCase: false })
 }
 
 describe("IOCLiveStatus", () => {
diff --git a/src/components/deployments/DeploymentDetailFetcher.js b/src/components/deployments/DeploymentDetailFetcher.js
index ea2638e3..5d464cfc 100644
--- a/src/components/deployments/DeploymentDetailFetcher.js
+++ b/src/components/deployments/DeploymentDetailFetcher.js
@@ -1,13 +1,13 @@
 import { useEffect } from "react";
 import { useTagsAndCommitIds, useCSentryHost } from "../../api/SwaggerApi";
 
-export function DeploymentDetailFetcher({ deployment, index, setDeployments }) {
-  function onError(message) {
-    console.log(message);
-  }
+function onError(message) {
+  console.warn(message);
+}
 
+export function DeploymentDetailFetcher({ deployment, index, setDeployments }) {
   const [tagOrCommitId, getTagOrCommitId] = useTagsAndCommitIds(onError);
-  const [host, getHost] = useCSentryHost();
+  const [host, getHost] = useCSentryHost(onError);
 
   useEffect(() => {
     getTagOrCommitId(deployment.gitProjectId, deployment.sourceVersion);
diff --git a/src/components/deployments/DeploymentJobOutput.js b/src/components/deployments/DeploymentJobOutput.js
index 997d2462..bf1a60ea 100644
--- a/src/components/deployments/DeploymentJobOutput.js
+++ b/src/components/deployments/DeploymentJobOutput.js
@@ -1,25 +1,24 @@
-import React, { useState, useCallback } from 'react';
+import React, { useCallback, useRef, useEffect } from 'react';
 import { LinearProgress, Typography, Container } from '@material-ui/core';
 import { useDeploymentJobLogById } from '../../api/SwaggerApi';
 import { Console } from "../common/Console/Console";
-import { Alert } from "@material-ui/lab";
 import { useSafePolling } from '../../hooks/Polling';
 
 const LOG_POLL_INTERVAL = 5000;
 export function DeploymentJobOutput({ deploymentJob }) {
-  const [error] = useState();
+  const [log, getLogById, /*reset*/, logLoading] = useDeploymentJobLogById();
+  const finalResultsNeeded = useRef(true);
 
-  // function onError(message) {
-  //   setError(message);
-  // }  
+  useEffect(() => {
+    finalResultsNeeded.current = true;
+  }, [deploymentJob.id]);
 
-  const [log, getLogById, /*reset*/, logLoading] = useDeploymentJobLogById();
   const getLog = useCallback(() => {
-    getLogById(deploymentJob.id);
-  },
-    // eslint warns here, 
-    // but we actually do want the log to update every time the deploymentJob updates
-    [deploymentJob, deploymentJob.id, getLogById]
+    if (!deploymentJob.finished || finalResultsNeeded.current) {
+      getLogById(deploymentJob.id);
+      finalResultsNeeded.current = !deploymentJob.finished;
+    }
+  }, [deploymentJob.finished, deploymentJob.id, getLogById]
   )
   useSafePolling(getLog, logLoading, LOG_POLL_INTERVAL)
 
@@ -43,22 +42,19 @@ export function DeploymentJobOutput({ deploymentJob }) {
 
   return (
     <Container maxWidth='xl'>
-      {error ?
-        <Alert severity="error">{error}</Alert>
+      {log ?
+        <div style={{
+          width: "100%",
+        }}>
+          <Console
+            html={log.stdoutHtml}
+            dataReady={dataReady}
+            title="AWX job details"
+            dialogHeader={header}
+          />
+        </div>
         :
-        log ?
-          <div style={{
-            width: "100%",
-          }}>
-            <Console
-              html={log.stdoutHtml}
-              dataReady={dataReady}
-              title="AWX job details"
-              dialogHeader={header}
-            />
-          </div>
-          :
-          <div style={{ width: "100%" }}><LinearProgress color="primary" /></div>
+        <div style={{ width: "100%" }}><LinearProgress color="primary" /></div>
       }
     </Container>
   )
-- 
GitLab