consul-templaterb 1.18.5 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,10 +5,10 @@ class ServiceTimeline {
5
5
  this.fetchRessource(true);
6
6
  this.serviceList = $("#service-list");
7
7
  this.serviceFilter = $("#service-filter");
8
- this.serviceFilter.keyup(debounce(this.filterService, 250));
8
+ this.serviceFilter.keyup(debounce('timeline-service-filter-keyup', this.filterService, 250));
9
9
  this.serviceInstanceFilter = '';
10
10
  this.instanceFilter = $("#instance-filter");
11
- this.instanceFilter.keyup(debounce(this.doFilter, 250));
11
+ this.instanceFilter.keyup(debounce('timeline-instance-filter-keyup', this.doFilter, 250));
12
12
  this.refresh = parseInt(refresh);
13
13
  this.filterStatus = null;
14
14
  this.refreshTimeout = null;
@@ -299,13 +299,11 @@ class ServiceTimeline {
299
299
  var filterValue = $('#instance-filter')[0].value;
300
300
  var serviceName = serviceTimeline.serviceInstanceFilter;
301
301
  var serviceEvaluator = function(){return true};
302
- var stylesheetText = '';
302
+ var showServiceColumn = true;
303
303
  if (serviceName != '' && serviceName != 'All') {
304
- stylesheetText = '.serviceCol { display: none; }';
304
+ showServiceColumn = false;
305
305
  serviceEvaluator = function(e){ return e.service === serviceName }
306
306
  }
307
- // Show / hide .serviceCol content
308
- document.getElementById('serviceCol').textContent = stylesheetText;
309
307
  var maxRows = document.getElementById("maxRows").value;
310
308
  //$("#service-title").html(service['name']);
311
309
  var tableBody = $('#all-events > tbody');
@@ -429,7 +427,9 @@ class ServiceTimeline {
429
427
  timeElement.setAttribute('title', fullTimestamp + '\nX-Consul-Index: ' +e.idx);
430
428
  this.buildCell(row, 'td', 'ts', timeElement);
431
429
  }
432
- this.buildCell(row, 'td', 'lookup serviceName serviceCol', document.createTextNode(e.service));
430
+ if (showServiceColumn) {
431
+ this.buildCell(row, 'td', 'lookup serviceName serviceCol', document.createTextNode(e.service));
432
+ }
433
433
  var text = e.instance;
434
434
  if (e.instance_info && e.instance_info.node) {
435
435
  text = e.instance_info.node;
@@ -512,5 +512,10 @@ class ServiceTimeline {
512
512
  if (this.data.length > 1) {
513
513
  this.lastEntryLoaded = this.data[this.data.length - 1];
514
514
  }
515
+ if (showServiceColumn) {
516
+ $('.serviceCol').show();
517
+ } else {
518
+ $('.serviceCol').hide();
519
+ }
515
520
  }
516
521
  }
@@ -0,0 +1,317 @@
1
+ class ConsulUIManager {
2
+ constructor(resourceURL) {
3
+ this.resourceURL = resourceURL;
4
+ }
5
+
6
+ async fetchResource() {
7
+ const response = await fetch(this.resourceURL);
8
+ const result = await response.json();
9
+ this.data = result;
10
+ await this.initResource(result);
11
+ }
12
+
13
+ async initResource(data) {}
14
+ }
15
+
16
+ class SideSelector {
17
+ constructor(
18
+ filterElement,
19
+ listElement,
20
+ counterElement,
21
+ URLLabelFilter,
22
+ URLLabelSelected,
23
+ activateFavorite
24
+ ) {
25
+ this.filterElement = filterElement;
26
+ this.listElement = listElement;
27
+ this.counterElement = counterElement;
28
+ this.elements = {}
29
+ this.filterElement.keyup(debounce('side-selector-filter-element-keyup', this.updateFilter.bind(this), 250));
30
+
31
+ this.URLLabelFilter = URLLabelFilter;
32
+ this.URLLabelSelected = URLLabelSelected;
33
+
34
+ this.selectedItem = new URL(location.href).searchParams.get(
35
+ URLLabelSelected
36
+ );
37
+ this.filterValue = new URL(location.href).searchParams.get(URLLabelFilter);
38
+ if (this.filterValue == null) {
39
+ this.filterValue = "";
40
+ }
41
+ this.filterElement.val(this.filterValue);
42
+ this.activateFavorite = activateFavorite;
43
+ if (this.activateFavorite) {
44
+ this.favorites = new Favorites("favorite_services");
45
+ }
46
+ this.showProxies = false;
47
+ }
48
+
49
+ prepareData() {
50
+ for (var key in this.data) {
51
+ this.elements[key] = this.elementGenerator(key, this.data[key]);
52
+ }
53
+ }
54
+
55
+ updateFilter() {
56
+ this.filterValue = this.filterElement.val();
57
+ updateURL(this.URLLabelFilter, this.filterValue);
58
+ this.refreshList();
59
+ }
60
+
61
+ refreshList() {
62
+ this.listElement.html("");
63
+ var filter;
64
+ try {
65
+ filter = new RegExp(this.filterValue);
66
+ } catch (e) {
67
+ var safeReg = this.filterValue.replace(/[-[\]{}()*+?.,\\^$|]/g, "\\$&");
68
+ console.log(
69
+ "Failed to compile regexp for '" +
70
+ this.filterValue +
71
+ "', using strict lookup due to: " +
72
+ e
73
+ );
74
+ filter = new RegExp(safeReg);
75
+ }
76
+ var selectItem = null;
77
+ var selectElement = null;
78
+ var elementTotal = 0;
79
+
80
+ if (this.activateFavorite) {
81
+ var favList = this.favorites.getAsArray();
82
+ var favDict = this.favorites.favorites;
83
+ for (var i in favList) {
84
+ if (favList[i] in this.data) {
85
+ if (this.matchElement(favList[i], this.data[favList[i]], filter)) {
86
+ if (selectItem == null || this.selectedItem == favList[i]) {
87
+ selectItem = favList[i];
88
+ selectElement = this.elements[favList[i]];
89
+ }
90
+ elementTotal++;
91
+ this.listElement.append(this.elements[favList[i]]);
92
+ }
93
+ }
94
+ }
95
+ } else {
96
+ var favDict = {};
97
+ }
98
+
99
+ for (var key in this.data) {
100
+ if (!(key in favDict) && this.matchElement(key, this.data[key], filter)) {
101
+ if (selectItem == null || this.selectedItem == key) {
102
+ selectItem = key;
103
+ selectElement = this.elements[key];
104
+ }
105
+ this.listElement.append(this.elements[key]);
106
+ elementTotal++;
107
+ }
108
+ }
109
+ this.elementTotal = elementTotal;
110
+ this.counterElement.html(this.elementTotal);
111
+ if (selectElement) {
112
+ selectElement.scrollIntoView();
113
+ }
114
+ this.selectItem(selectElement, selectItem);
115
+ }
116
+
117
+ onClickElement(source, selected) {
118
+ this.selectItem(source, selected);
119
+ }
120
+
121
+ selectItem(element, item) {
122
+ if (this.selectedElem != null) {
123
+ this.selectedElem.classList.remove("active");
124
+ }
125
+ this.selectedElem = element;
126
+ if (element != null) {
127
+ this.selectedElem.classList.add("active");
128
+ }
129
+
130
+ this.selectedItem = item;
131
+
132
+ updateURL(this.URLLabelSelected, item);
133
+ }
134
+ }
135
+
136
+ class MainSelector {
137
+ constructor(listElement, filterElement, counterElement, maxDisplayElement, URLLabelFilter, URLLabelStatus) {
138
+ this.listElement = listElement;
139
+ this.filterElement = filterElement;
140
+ this.filterElement.keyup(debounce('main-selector-filter-element', this.updateFilter.bind(this), 250));
141
+ this.selectorStatus = {}
142
+ this.counterElement = counterElement;
143
+ this.maxDisplayElement = maxDisplayElement;
144
+ this.maxDisplayElement.get(0).addEventListener("change", this.maxDisplaySelection.bind(this));
145
+ this.URLLabelFilter = URLLabelFilter
146
+ this.URLLabelStatus = URLLabelStatus
147
+
148
+ this.filterValue = new URL(location.href).searchParams.get(URLLabelFilter);
149
+ if (this.filterValue == null) {
150
+ this.filterValue = "";
151
+ }
152
+ this.filterElement.val(this.filterValue)
153
+
154
+ this.statusFilter = new URL(location.href).searchParams.get(URLLabelStatus);
155
+ updateFilterDisplay(this.statusFilter);
156
+ console.log("filter", this.statusFilter);
157
+
158
+ this.maxDisplayed = this.maxDisplayElement.val();
159
+ }
160
+
161
+ initSelector(data) {
162
+ this.data = data;
163
+ for (var key in this.data) {
164
+ this.data[key]["element"] = this.elementGenerator(this.data[key]);
165
+ }
166
+ this.refreshList();
167
+ }
168
+
169
+ maxDisplaySelection() {
170
+ this.maxDisplayed = this.maxDisplayElement.val();
171
+ this.refreshList();
172
+ }
173
+
174
+ refreshList() {
175
+ this.listElement.html("");
176
+ try {
177
+ var filter = new RegExp(this.filterValue);
178
+ } catch (e) {
179
+ var safeReg = this.filterValue.replace(/[-[\]{}()*+?.,\\^$|]/g, "\\$&");
180
+ console.log(
181
+ "Failed to compile regexp for '" +
182
+ this.filterValue +
183
+ "', using strict lookup due to: " +
184
+ e
185
+ );
186
+ var filter = new RegExp(safeReg);
187
+ }
188
+
189
+ this.selectorStatus = {}
190
+ var displayedCounter = 0
191
+ for (var key in this.data) {
192
+ if (this.matchElement(this.data[key], filter)) {
193
+ if (this.maxDisplayed == "all" ||  displayedCounter < this.maxDisplayed) {
194
+ this.listElement.append(this.data[key]["element"]);
195
+ displayedCounter++
196
+ }
197
+
198
+ var state = this.getStatus(this.data[key]);
199
+ this.selectorStatus[state] = (this.selectorStatus[state] || 0) + 1;
200
+ this.selectorStatus['total'] = (this.selectorStatus['total'] || 0) + 1;
201
+ }
202
+ }
203
+ this.counterElement.html(displayedCounter);
204
+ this.updateStatusCounters();
205
+ }
206
+
207
+ onClickFilter(source, status) {
208
+ if (this.statusFilter == status) {
209
+ this.statusFilter = null;
210
+ } else {
211
+ this.statusFilter = status;
212
+ }
213
+
214
+ updateURL(this.URLLabelStatus, this.statusFilter);
215
+ updateFilterDisplay(this.statusFilter);
216
+ this.refreshList();
217
+ }
218
+
219
+ updateFilter() {
220
+ //console.log('filter updated from ', this.filterValue, 'to', this.filterElement.val());
221
+ this.filterValue = this.filterElement.val();
222
+ updateURL(this.URLLabelFilter, this.filterValue);
223
+ this.refreshList();
224
+ }
225
+ }
226
+
227
+ class CodeDisplayer {
228
+ constructor(codeElement, titleElement) {
229
+ this.codeElement = codeElement
230
+ this.titleElement = titleElement
231
+ }
232
+
233
+ displayData(key, code) {
234
+ this.titleElement.html(key);
235
+ this.codeElement.text(code);
236
+ this.codeElement.removeClass();
237
+
238
+ $('pre code').each(function(i, block) {
239
+ hljs.highlightBlock(block);
240
+ });
241
+ resizeWrapper('data-wrapper', 'kv-data');
242
+ }
243
+ }
244
+
245
+ class DisplayFlag {
246
+ constructor(element, callback) {
247
+ this.state = element.checked;
248
+ this.callback = callback;
249
+ this.element = element;
250
+
251
+ var obj = this;
252
+ element.addEventListener("click", function() {
253
+ obj.onClickElement();
254
+ });
255
+ }
256
+
257
+ onClickElement() {
258
+ this.state = this.element.checked;
259
+ this.callback();
260
+ }
261
+ }
262
+
263
+ class Favorites {
264
+ constructor(favoriteKey) {
265
+ this.key = favoriteKey;
266
+ const all = (localStorage.getItem(this.key) || "")
267
+ .split(",")
268
+ .filter(e => e != "");
269
+ this.favorites = {};
270
+ for (var i in all) {
271
+ this.favorites[all[i]] = true;
272
+ }
273
+ }
274
+
275
+ saveFavorites() {
276
+ let fav = [];
277
+ for (var i in this.favorites) {
278
+ if (!this.favorites[i]) {
279
+ continue;
280
+ }
281
+ fav.push(i);
282
+ }
283
+ localStorage.setItem(this.key, fav.join());
284
+ }
285
+
286
+ getAsArray() {
287
+ return Object.keys(this.favorites);
288
+ }
289
+
290
+ buildButton(serviceName) {
291
+ const btn = document.createElement("button");
292
+ btn.className = "favorite";
293
+ btn.setAttribute("title", "Add/Remove from favorites");
294
+
295
+ if (this.favorites[serviceName]) {
296
+ btn.className += " favorited";
297
+ }
298
+
299
+ var obj = this;
300
+ btn.addEventListener("click", function() {
301
+ obj.toggleFav(this, serviceName);
302
+ });
303
+
304
+ return btn;
305
+ }
306
+
307
+ toggleFav(source, serviceName) {
308
+ if (serviceName in this.favorites) {
309
+ delete this.favorites[serviceName];
310
+ source.classList.remove("favorited");
311
+ } else {
312
+ this.favorites[serviceName] = true;
313
+ source.classList.add("favorited");
314
+ }
315
+ this.saveFavorites();
316
+ }
317
+ }
@@ -1,455 +1,483 @@
1
1
  function buildServiceStatus(service) {
2
- var serviceStatus = {};
2
+ var serviceStatus = {};
3
+ for (var key in service['instances']) {
4
+ var instance = service['instances'][key];
5
+ var state = nodeState(instance.checks);
3
6
 
4
- for (var key in service['instances']) {
5
- var instance = service['instances'][key];
6
- var state = nodeState(instance.checks);
7
-
8
- serviceStatus[state] = (serviceStatus[state] || 0) + 1;
9
- serviceStatus['total'] = (serviceStatus['total'] || 0) + 1;
10
- }
11
-
12
- return serviceStatus;
7
+ serviceStatus[state] = (serviceStatus[state] || 0) + 1;
8
+ serviceStatus['total'] = (serviceStatus['total'] || 0) + 1;
9
+ }
10
+ service["status"] = serviceStatus
11
+ return serviceStatus;
13
12
  }
14
13
 
15
- function debounce(func, wait) {
16
- var timeout;
17
- return function() {
18
- var context = this, args = arguments;
19
- var later = function() {
20
- timeout = null;
21
- func.apply(context, args);
22
- };
23
- clearTimeout(timeout);
24
- timeout = setTimeout(later, wait);
25
- };
14
+ var timeouts = {};
15
+
16
+ function debounce(name, func, wait) {
17
+ return function() {
18
+ var context = this,
19
+ args = arguments;
20
+ var later = function () {
21
+ timeouts[name] = null;
22
+ func.apply(context, args);
23
+ };
24
+ if (timeouts[name] != null) {
25
+ //console.log("Clearing timeout", name);
26
+ clearTimeout(timeouts[name]);
27
+ }
28
+ timeouts[name] = setTimeout(later, wait);
29
+ };
26
30
  };
27
31
 
28
32
  function padDateUnit(x) {
29
- return x > 9 ? x : '0' + x;
33
+ return x > 9 ? x : '0' + x;
30
34
  }
31
35
 
32
36
  function formatDate(date) {
33
- return padDateUnit(date.getMonth()+1) + "/" + padDateUnit(date.getDate()) + " " + padDateUnit(date.getHours()) + ':' + padDateUnit(date.getMinutes()) + ':' + padDateUnit(date.getSeconds());
37
+ return padDateUnit(date.getMonth() + 1) + "/" + padDateUnit(date.getDate()) + " " + padDateUnit(date.getHours()) + ':' + padDateUnit(date.getMinutes()) + ':' + padDateUnit(date.getSeconds());
34
38
  }
35
39
 
36
40
  function indexOfTimelineEvent(e) {
37
- if (e == null) {
38
- return 'k/0000000000/0000/0000';
39
- }
40
- return 'k/' + e.idx.toString().padStart(10, '0') + '/' + e.service + '/' + e.instance;
41
+ if (e == null) {
42
+ return 'k/0000000000/0000/0000';
43
+ }
44
+ return 'k/' + e.idx.toString().padStart(10, '0') + '/' + e.service + '/' + e.instance;
41
45
  }
42
46
 
43
47
  function nodeState(checks) {
44
- status='passing';
45
- for (var checkKey in checks) {
46
- switch(checks[checkKey]['status']) {
47
- case 'passing': break;
48
- case 'warning': status='warning'; break;
49
- case 'critical': return 'critical'; break;
48
+ status = 'passing';
49
+ for (var checkKey in checks) {
50
+ switch (checks[checkKey]['status']) {
51
+ case 'passing':
52
+ break;
53
+ case 'warning':
54
+ status = 'warning';
55
+ break;
56
+ case 'critical':
57
+ return 'critical';
58
+ break;
59
+ }
50
60
  }
51
- }
52
- return status;
61
+ return status;
53
62
  }
54
63
 
55
64
  supported_protocols = ['https', 'http', 'sftp', 'ftp', 'ssh', 'telnet']
56
65
 
57
66
  function serviceTitleGenerator(instance) {
58
- var protocol = null;
59
- for (i in supported_protocols) {
60
- var protoc = supported_protocols[i]
61
- if (instance.tags.includes(protoc)) {
62
- protocol = protoc + '://';
63
- break;
67
+ var protocol = null;
68
+ for (i in supported_protocols) {
69
+ var protoc = supported_protocols[i]
70
+ if (instance.tags.includes(protoc)) {
71
+ protocol = protoc + '://';
72
+ break;
73
+ }
64
74
  }
65
- }
66
-
67
- var htmlTitle = document.createElement('h5');
68
- htmlTitle.setAttribute('title', 'Node Name: ' + instance.name +
69
- '\nAddress: ' + instance.addr +
70
- '\nService ID: ' + instance.id +
71
- '\nService Port: ' + instance.port);
72
-
73
- htmlTitle.setAttribute('class', 'instance-name');
74
- var instanceLink = document.createElement('a');
75
- var appendPort = "";
76
- if (instance.port > 0) {
77
- appendPort = ':' + instance.port;
78
- }
79
- if (protocol != null) {
80
- instanceLink.setAttribute('href', protocol + instance.addr + appendPort);
81
- instanceLink.setAttribute('target', '_blank');
82
- }
83
-
84
- instanceLink.appendChild(document.createTextNode(instance.name + appendPort));
85
- htmlTitle.appendChild(instanceLink);
86
- htmlTitle.appendChild(document.createTextNode(' '));
87
- htmlTitle.appendChild(document.createTextNode(instance.addr));
88
-
89
- return htmlTitle;
75
+
76
+ var htmlTitle = document.createElement('h5');
77
+ htmlTitle.setAttribute('title', 'Node Name: ' + instance.name +
78
+ '\nAddress: ' + instance.addr +
79
+ '\nService ID: ' + instance.id +
80
+ '\nService Port: ' + instance.port);
81
+
82
+ htmlTitle.setAttribute('class', 'instance-name');
83
+ var instanceLink = document.createElement('a');
84
+ var appendPort = "";
85
+ if (instance.port > 0) {
86
+ appendPort = ':' + instance.port;
87
+ }
88
+ if (protocol != null) {
89
+ instanceLink.setAttribute('href', protocol + instance.addr + appendPort);
90
+ instanceLink.setAttribute('target', '_blank');
91
+ }
92
+
93
+ instanceLink.appendChild(document.createTextNode(instance.name + appendPort));
94
+ htmlTitle.appendChild(instanceLink);
95
+ htmlTitle.appendChild(document.createTextNode(' '));
96
+ htmlTitle.appendChild(document.createTextNode(instance.addr));
97
+
98
+ return htmlTitle;
90
99
  }
91
100
 
92
101
  function nodeNameGenator(nodename, nodeaddr) {
93
- var protocol = 'ssh://'
102
+ var protocol = 'ssh://'
94
103
 
95
- var htmlTitle = document.createElement('h5');
104
+ var htmlTitle = document.createElement('h5');
96
105
 
97
- var instanceLink = document.createElement('a');
98
- instanceLink.setAttribute('class', 'instance-name');
99
- if (protocol != null) {
100
- instanceLink.setAttribute('href', protocol + nodeaddr);
101
- instanceLink.setAttribute('target', '_blank');
102
- }
103
- instanceLink.appendChild(document.createTextNode(nodename));
104
- htmlTitle.appendChild(instanceLink);
106
+ var instanceLink = document.createElement('a');
107
+ instanceLink.setAttribute('class', 'instance-name');
108
+ if (protocol != null) {
109
+ instanceLink.setAttribute('href', protocol + nodeaddr);
110
+ instanceLink.setAttribute('target', '_blank');
111
+ }
112
+ instanceLink.appendChild(document.createTextNode(nodename));
113
+ htmlTitle.appendChild(instanceLink);
105
114
 
106
- return htmlTitle;
115
+ return htmlTitle;
107
116
  }
108
117
 
109
118
  function nodeAddressGenator(nodeaddr) {
110
- var htmlAddress = document.createElement('h5');
111
- htmlAddress.className = 'instance-addr lookup';
112
- htmlAddress.appendChild(document.createTextNode(nodeaddr));
113
- return htmlAddress;
119
+ var htmlAddress = document.createElement('h5');
120
+ htmlAddress.className = 'instance-addr lookup';
121
+ htmlAddress.appendChild(document.createTextNode(nodeaddr));
122
+ return htmlAddress;
114
123
  }
115
124
 
116
125
  function nodeMetaGenerator(nodeMetaTags) {
117
- var metaTags = document.createElement('div');
118
- metaTags.setAttribute('title', 'Node Meta')
119
- metaTags.className = 'node-meta';
120
- for (var tagKey in nodeMetaTags) {
121
- if(!nodeMetaTags[tagKey]) {
122
- continue;
126
+ var metaTags = document.createElement('div');
127
+ metaTags.setAttribute('title', 'Node Meta')
128
+ metaTags.className = 'node-meta';
129
+ for (var tagKey in nodeMetaTags) {
130
+ if (!nodeMetaTags[tagKey]) {
131
+ continue;
132
+ }
133
+ var metaTag = document.createElement('span');
134
+ metaTag.setAttribute('class', 'badge badge-primary mx-1 lookup');
135
+ metaTag.appendChild(document.createTextNode(tagKey + ':' + nodeMetaTags[tagKey]));
136
+ metaTags.appendChild(metaTag);
123
137
  }
124
- var metaTag = document.createElement('span');
125
- metaTag.setAttribute('class', 'badge badge-primary mx-1 lookup');
126
- metaTag.appendChild(document.createTextNode(tagKey + ':' + nodeMetaTags[tagKey]));
127
- metaTags.appendChild(metaTag);
128
- }
129
- return metaTags;
138
+ return metaTags;
130
139
  }
131
140
 
132
141
  function tagsGenerator(instanceTags) {
133
- var tags = document.createElement('div');
134
-
135
- tags.className = 'instance-tags';
136
- tags.setAttribute('title', 'Tags of Service');
137
- for (var tagKey in instanceTags) {
138
- var tag = document.createElement('span');
139
- tag.setAttribute('class', 'badge badge-secondary mx-1 lookup');
140
- tag.appendChild(document.createTextNode(instanceTags[tagKey]));
141
- tags.appendChild(tag);
142
- }
143
- return tags;
142
+ var tags = document.createElement('div');
143
+
144
+ tags.className = 'instance-tags';
145
+ tags.setAttribute('title', 'Tags of Service');
146
+ for (var tagKey in instanceTags) {
147
+ var tag = document.createElement('span');
148
+ tag.setAttribute('class', 'badge badge-secondary mx-1 lookup');
149
+ tag.appendChild(document.createTextNode(instanceTags[tagKey]));
150
+ tags.appendChild(tag);
151
+ }
152
+ return tags;
144
153
  }
145
154
 
146
155
  function connectGenerator(instance) {
147
- var connectItem = document.createElement('div');
148
- var connectValue = instance['connect']
149
- if (connectValue != null && connectValue["Proxy"]) {
150
- connectItem.setAttribute('class', 'connect-enabled');
151
- var badge = document.createElement("span");
152
- badge.setAttribute("class", "badge badge-primary");
153
- badge.appendChild(document.createTextNode("Consul Connect Enabled"));
154
- connectItem.appendChild(badge);
155
- var content = document.createElement("pre");
156
- content.setAttribute("class", "connect-data");
157
- var code = document.createElement("code");
158
- code.setAttribute("class", "connect-source");
159
- code.appendChild(document.createTextNode(JSON.stringify(connectValue)));
160
- content.appendChild(code);
161
- connectItem.appendChild(content);
162
- return connectItem;
163
- } else {
164
- connectItem.setAttribute('class', 'connect-disabled');
165
- }
166
- return connectItem
156
+ var connectItem = document.createElement('div');
157
+ var connectValue = instance['connect']
158
+ if (connectValue != null && connectValue["Proxy"]) {
159
+ connectItem.setAttribute('class', 'connect-enabled');
160
+ var badge = document.createElement("span");
161
+ badge.setAttribute("class", "badge badge-primary");
162
+ badge.appendChild(document.createTextNode("Consul Connect Enabled"));
163
+ connectItem.appendChild(badge);
164
+ var content = document.createElement("pre");
165
+ content.setAttribute("class", "connect-data");
166
+ var code = document.createElement("code");
167
+ code.setAttribute("class", "connect-source");
168
+ code.appendChild(document.createTextNode(JSON.stringify(connectValue)));
169
+ content.appendChild(code);
170
+ connectItem.appendChild(content);
171
+ return connectItem;
172
+ } else {
173
+ connectItem.setAttribute('class', 'connect-disabled');
174
+ }
175
+ return connectItem
167
176
  }
168
177
 
169
178
  function serviceMetaGenerator(instanceMeta) {
170
- var top = document.createElement('div');
171
- top.className = 'instance-meta';
172
- if (instanceMeta) {
173
- var container = document.createElement('dl');
174
- top.appendChild(container);
175
- container.className = 'row';
176
- for (var meta in instanceMeta) {
177
- var metaH = document.createElement('dt');
178
- metaH.className = 'col-sm-4 lookup';
179
- metaH.appendChild(document.createTextNode(meta));
180
- container.appendChild(metaH);
181
- var metaVH = document.createElement('dd');
182
- metaVH.className = 'col-sm-8 lookup';
183
- metaVH.appendChild(document.createTextNode(instanceMeta[meta]));
184
- container.appendChild(metaVH);
179
+ var top = document.createElement('div');
180
+ top.className = 'instance-meta';
181
+ if (instanceMeta) {
182
+ var container = document.createElement('dl');
183
+ top.appendChild(container);
184
+ container.className = 'row';
185
+ for (var meta in instanceMeta) {
186
+ var metaH = document.createElement('dt');
187
+ metaH.className = 'col-sm-4 lookup';
188
+ metaH.appendChild(document.createTextNode(meta));
189
+ container.appendChild(metaH);
190
+ var metaVH = document.createElement('dd');
191
+ metaVH.className = 'col-sm-8 lookup';
192
+ metaVH.appendChild(document.createTextNode(instanceMeta[meta]));
193
+ container.appendChild(metaVH);
194
+ }
185
195
  }
186
- }
187
- return top;
196
+ return top;
188
197
  }
189
198
 
190
199
  function weightsGenerator(instanceWeights, instanceStatus) {
191
- var weights = document.createElement('div');
192
- if (instanceWeights != null) {
193
- weights.setAttribute('class', 'weights weight-passing badge badge-' + toCSSClass(instanceStatus));
194
- weights.appendChild(document.createTextNode("Weights: "));
195
- {
196
- var passing = document.createElement("span");
197
- passing.setAttribute("class", "weight-passing badge badge-success");
198
- passing.appendChild(document.createTextNode(instanceWeights['Passing']));
199
- passing.setAttribute('title', "DNS Weight when in warning state")
200
- weights.appendChild(passing);
201
- }
202
- weights.appendChild(document.createTextNode(' '));
203
- {
204
- var warning = document.createElement("span");
205
- warning.setAttribute("class", "weight-warning badge badge-warning");
206
- warning.setAttribute('title', "DNS Weight when in warning state")
207
- warning.appendChild(document.createTextNode(instanceWeights['Warning']));
208
- weights.appendChild(warning);
200
+ var weights = document.createElement('div');
201
+ if (instanceWeights != null) {
202
+ weights.setAttribute('class', 'weights weight-passing badge badge-' + toCSSClass(instanceStatus));
203
+ weights.appendChild(document.createTextNode("Weights: ")); {
204
+ var passing = document.createElement("span");
205
+ passing.setAttribute("class", "weight-passing badge badge-success");
206
+ passing.appendChild(document.createTextNode(instanceWeights['Passing']));
207
+ passing.setAttribute('title', "DNS Weight when in warning state")
208
+ weights.appendChild(passing);
209
+ }
210
+ weights.appendChild(document.createTextNode(' ')); {
211
+ var warning = document.createElement("span");
212
+ warning.setAttribute("class", "weight-warning badge badge-warning");
213
+ warning.setAttribute('title', "DNS Weight when in warning state")
214
+ warning.appendChild(document.createTextNode(instanceWeights['Warning']));
215
+ weights.appendChild(warning);
216
+ }
217
+ return weights;
218
+ } else {
219
+ weights.setAttribute('class', 'weights-absent');
209
220
  }
210
- return weights;
211
- } else {
212
- weights.setAttribute('class', 'weights-absent');
213
- }
214
- return weights
221
+ return weights
215
222
  }
216
223
 
217
224
  function toCSSClass(state) {
218
- switch(state) {
219
- case 'passing': return 'success';
220
- case 'critical': return 'danger';
221
- }
222
- return state;
225
+ switch (state) {
226
+ case 'passing':
227
+ return 'success';
228
+ case 'critical':
229
+ return 'danger';
230
+ }
231
+ return state;
223
232
  }
224
233
 
225
234
  function servicesGenerator(instanceServices) {
226
- var services = document.createElement('div');
227
- services.className = 'instance-services';
228
- services.appendChild(document.createTextNode("Services: "));
229
- services.appendChild(document.createElement('br'));
230
- for (var serviceKey in instanceServices) {
231
- var service = document.createElement('a');
232
- var serviceName = instanceServices[serviceKey]['Service']['Service'];
233
- var servicePort = instanceServices[serviceKey]['Service']['Port'];
234
- service.setAttribute('class', 'btn btn-sm m-1 lookup');
235
- service.setAttribute('target', '_blank');
236
- nodeAddr = instanceServices[serviceKey]['Service']['Address'];
237
- service.setAttribute('href', 'http://' + nodeAddr + ':' + servicePort);
238
- service.classList.add('btn-outline-'+toCSSClass(nodeState(instanceServices[serviceKey]['Checks'])))
239
- service.appendChild(document.createTextNode(serviceName + ':' + servicePort));
240
- services.appendChild(service);
241
- }
242
- return services;
235
+ var services = document.createElement('div');
236
+ services.className = 'instance-services';
237
+ services.appendChild(document.createTextNode("Services: "));
238
+ services.appendChild(document.createElement('br'));
239
+ for (var serviceKey in instanceServices) {
240
+ var service = document.createElement('a');
241
+ var serviceName = instanceServices[serviceKey]['Service']['Service'];
242
+ var servicePort = instanceServices[serviceKey]['Service']['Port'];
243
+ service.setAttribute('class', 'btn btn-sm m-1 lookup');
244
+ service.setAttribute('target', '_blank');
245
+ nodeAddr = instanceServices[serviceKey]['Service']['Address'];
246
+ service.setAttribute('href', 'http://' + nodeAddr + ':' + servicePort);
247
+ service.classList.add('btn-outline-' + toCSSClass(nodeState(instanceServices[serviceKey]['Checks'])))
248
+ service.appendChild(document.createTextNode(serviceName + ':' + servicePort));
249
+ services.appendChild(service);
250
+ }
251
+ return services;
243
252
  }
244
253
 
245
254
  function checksStatusGenerator(instance, prefix) {
246
- var instanceChecks = instance.checks;
247
- var checks = document.createElement('div');
248
- checks.className = 'checks';
249
- checks.setAttribute('title', 'Checks of Node/Service')
250
-
251
- for (var checkKey in instanceChecks) {
252
- var checkInstance = instanceChecks[checkKey];
253
- var checkId = prefix + '::' + checkInstance.checkid;
254
- var btn = 'btn-' + toCSSClass(instanceChecks[checkKey]['status'])
255
- var check = document.createElement('div');
256
-
257
- var btnCheck = document.createElement('button');
258
- btnCheck.setAttribute('class','btn ' + btn + ' btn-sm m-1');
259
- btnCheck.setAttribute('type', 'button');
260
- btnCheck.setAttribute('data-toggle', 'collapse');
261
- btnCheck.setAttribute('data-target', '#' + checkId);
262
- btnCheck.setAttribute('aria-expanded', 'false');
263
- btnCheck.setAttribute('title', checkInstance.checkid);
264
-
265
- btnCheck.appendChild(document.createTextNode(instanceChecks[checkKey]['name']));
266
-
267
- check.appendChild(btnCheck);
268
-
269
- var collapseCheck = document.createElement('div');
270
- collapseCheck.setAttribute('class', 'collapse')
271
- collapseCheck.setAttribute('id', checkId)
272
-
273
- var cardCheck = document.createElement('div');
274
- cardCheck.setAttribute('class', 'card card-body p-3 m-1 mb-2');
275
-
276
- var notes = document.createElement('table');
277
- notes.setAttribute('class', 'table table-hover mb-0');
278
-
279
- var dataToDisplay = ['notes', 'output'];
280
- for (var index in dataToDisplay) {
281
- var tr = document.createElement('tr');
282
- var td1 = document.createElement('td');
283
- var td2 = document.createElement('td');
284
- var fieldName = dataToDisplay[index].replace(/\b\w/g, l => l.toUpperCase());
285
- td1.appendChild(document.createTextNode(fieldName + ': '));
286
- var target = td2
287
- if (index != 1) {
288
- target = document.createElement('div');
289
- target.setAttribute("class", "check-notes")
290
- } else {
291
- // Notes are rendered as plain text
292
- target = document.createElement('pre');
293
- target.setAttribute("class", "check-output")
294
- }
295
- target.appendChild(document.createTextNode(instanceChecks[checkKey][dataToDisplay[index]]));
296
- td2.appendChild(target)
297
- tr.appendChild(td1);
298
- tr.appendChild(td2);
299
- notes.appendChild(tr);
255
+ var instanceChecks = instance.checks;
256
+ var checks = document.createElement('div');
257
+ checks.className = 'checks';
258
+ checks.setAttribute('title', 'Checks of Node/Service')
259
+
260
+ for (var checkKey in instanceChecks) {
261
+ var checkInstance = instanceChecks[checkKey];
262
+ var checkId = prefix + '::' + checkInstance.checkid;
263
+ var btn = 'btn-' + toCSSClass(instanceChecks[checkKey]['status'])
264
+ var check = document.createElement('div');
265
+
266
+ var btnCheck = document.createElement('button');
267
+ btnCheck.setAttribute('class', 'btn ' + btn + ' btn-sm m-1');
268
+ btnCheck.setAttribute('type', 'button');
269
+ btnCheck.setAttribute('data-toggle', 'collapse');
270
+ btnCheck.setAttribute('data-target', '#' + checkId);
271
+ btnCheck.setAttribute('aria-expanded', 'false');
272
+ btnCheck.setAttribute('title', checkInstance.checkid);
273
+
274
+ btnCheck.appendChild(document.createTextNode(instanceChecks[checkKey]['name']));
275
+
276
+ check.appendChild(btnCheck);
277
+
278
+ var collapseCheck = document.createElement('div');
279
+ collapseCheck.setAttribute('class', 'collapse')
280
+ collapseCheck.setAttribute('id', checkId)
281
+
282
+ var cardCheck = document.createElement('div');
283
+ cardCheck.setAttribute('class', 'card card-body p-3 m-1 mb-2');
284
+
285
+ var notes = document.createElement('table');
286
+ notes.setAttribute('class', 'table table-hover mb-0');
287
+
288
+ var dataToDisplay = ['notes', 'output'];
289
+ for (var index in dataToDisplay) {
290
+ var tr = document.createElement('tr');
291
+ var td1 = document.createElement('td');
292
+ var td2 = document.createElement('td');
293
+ var fieldName = dataToDisplay[index].replace(/\b\w/g, l => l.toUpperCase());
294
+ td1.appendChild(document.createTextNode(fieldName + ': '));
295
+ var target = td2
296
+ if (index != 1) {
297
+ target = document.createElement('div');
298
+ target.setAttribute("class", "check-notes")
299
+ } else {
300
+ // Notes are rendered as plain text
301
+ target = document.createElement('pre');
302
+ target.setAttribute("class", "check-output")
303
+ }
304
+ target.appendChild(document.createTextNode(instanceChecks[checkKey][dataToDisplay[index]]));
305
+ td2.appendChild(target)
306
+ tr.appendChild(td1);
307
+ tr.appendChild(td2);
308
+ notes.appendChild(tr);
309
+ }
310
+
311
+ cardCheck.appendChild(notes);
312
+ collapseCheck.appendChild(cardCheck);
313
+ check.appendChild(collapseCheck);
314
+ checks.appendChild(check)
300
315
  }
301
316
 
302
- cardCheck.appendChild(notes);
303
- collapseCheck.appendChild(cardCheck);
304
- check.appendChild(collapseCheck);
305
- checks.appendChild(check)
306
- }
307
-
308
- return checks;
317
+ return checks;
309
318
  }
310
319
 
311
320
  function resizeAll() {
312
- resizeWrapper('service-wrapper', 'service-list');
313
- resizeWrapper('instances-wrapper', 'instances-list');
321
+ resizeWrapper('service-wrapper', 'service-list');
322
+ resizeWrapper('instances-wrapper', 'instances-list');
314
323
  }
315
324
 
316
325
  function resizeInstances() {
317
- resizeWrapper('instances-wrapper', 'instances-list');
326
+ resizeWrapper('instances-wrapper', 'instances-list');
318
327
  }
319
328
 
320
329
  function resizeData() {
321
- resizeWrapper('keys-wrapper', 'keys-list');
322
- resizeWrapper('data-wrapper', 'kv-data');
330
+ resizeWrapper('keys-wrapper', 'keys-list');
331
+ resizeWrapper('data-wrapper', 'kv-data');
323
332
  }
324
333
 
325
334
  function resizeWrapper(wrapperId, wrapped) {
326
- var size = $(window).height() - $('#' + wrapperId).offset()["top"] - 20;
327
- $('#' + wrapperId).css("height", size);
335
+ var size = $(window).height() - $('#' + wrapperId).offset()["top"] - 20;
336
+ $('#' + wrapperId).css("height", size);
328
337
  }
329
338
 
330
339
  function createBadge(classes, data) {
331
- var badge = document.createElement('span');
332
- badge.setAttribute('class', 'badge mx-1');
333
- classesArray = classes.split(' ');
334
- for (var i = 0; i < classesArray.length; i++) {
335
- badge.classList.add(classesArray[i]);
336
- }
337
-
338
- badge.appendChild(document.createTextNode(data));
339
- return badge;
340
+ var badge = document.createElement('span');
341
+ badge.setAttribute('class', 'badge mx-1');
342
+ classesArray = classes.split(' ');
343
+ for (var i = 0; i < classesArray.length; i++) {
344
+ badge.classList.add(classesArray[i]);
345
+ }
346
+
347
+ badge.appendChild(document.createTextNode(data));
348
+ return badge;
340
349
  }
341
350
 
342
351
  function serviceMatcher(service, regex, showProxiesInList) {
343
- if(service.getElementsByClassName('service-name')[0].innerHTML.match(regex)) {
344
- if(!showProxiesInList && service.classList.contains('kind-connect-proxy')){
345
- return false;
352
+ if (service.getElementsByClassName('service-name')[0].innerHTML.match(regex)) {
353
+ if (!showProxiesInList && service.classList.contains('kind-connect-proxy')) {
354
+ return false;
355
+ }
356
+ return true;
346
357
  }
347
- return true;
348
- }
349
- var tags = service.getElementsByClassName('service-tags')[0].getElementsByClassName('badge');
358
+ var tags = service.getElementsByClassName('service-tags')[0].getElementsByClassName('badge');
350
359
 
351
- for (var i=0; i < tags.length; i++) {
352
- if(tags[i].innerHTML.match(regex)) {
353
- return true;
360
+ for (var i = 0; i < tags.length; i++) {
361
+ if (tags[i].innerHTML.match(regex)) {
362
+ return true;
363
+ }
354
364
  }
355
- }
356
-
357
- var sstatus = service.getAttribute('status')
358
- if(sstatus && sstatus.match(regex)) {
359
- return true;
360
- }
361
-
362
- return false;
365
+
366
+ var sstatus = service.getAttribute('status')
367
+ if (sstatus && sstatus.match(regex)) {
368
+ return true;
369
+ }
370
+
371
+ return false;
363
372
  }
364
373
 
365
374
  function keyMatcher(service, regex) {
366
- if(service.getElementsByClassName('key-name')[0].innerHTML.match(regex)) {
367
- return true;
368
- }
375
+ if (service.getElementsByClassName('key-name')[0].innerHTML.match(regex)) {
376
+ return true;
377
+ }
369
378
  }
370
379
 
371
380
  function hasMatches(instance, regex) {
372
- var toLookup = instance.getElementsByClassName('lookup');
373
- for (var i = 0 ; i < toLookup.length; i++) {
374
- if(toLookup[i].innerHTML.match(regex)) {
375
- return true;
381
+ var toLookup = instance.getElementsByClassName('lookup');
382
+ for (var i = 0; i < toLookup.length; i++) {
383
+ if (toLookup[i].innerHTML.match(regex)) {
384
+ return true;
385
+ }
376
386
  }
377
- }
378
- return false;
387
+ return false;
379
388
  }
380
389
 
381
390
  function instanceMatcher(instance, regex) {
382
- if(instance.getElementsByClassName('instance-name')[0].innerHTML.match(regex)) {
383
- return true;
384
- }
391
+ if (instance.getElementsByClassName('instance-name')[0].innerHTML.match(regex)) {
392
+ return true;
393
+ }
385
394
 
386
- return hasMatches(instance, regex);
395
+ return hasMatches(instance, regex);
387
396
  }
388
397
 
389
398
  function nodeMatcher(instance, regex) {
390
399
  instanceMatcher(instance, regex);
391
- if(instance.getElementsByClassName('instance-name')[0].innerHTML.match(regex)) {
392
- return true;
400
+ if (instance.getElementsByClassName('instance-name')[0].innerHTML.match(regex)) {
401
+ return true;
393
402
  }
394
403
 
395
404
  return hasMatches(instance, regex);
396
405
  }
397
406
 
398
407
  function getTagsNode(node) {
399
- tags = new Set([]);
400
- for (service in node['Service']) {
401
- for (tag in node['Service'][service]['Service']['Tags']) {
402
- tags.add(node['Service'][service]['Service']['Tags'][tag]);
408
+ tags = new Set([]);
409
+ for (service in node['Service']) {
410
+ for (tag in node['Service'][service]['Service']['Tags']) {
411
+ tags.add(node['Service'][service]['Service']['Tags'][tag]);
412
+ }
403
413
  }
404
- }
405
- return Array.from(tags);
414
+ return Array.from(tags);
406
415
  }
407
416
 
408
417
  function getChecksNode(node) {
409
- checks = [];
410
- for (service in node['Service']) {
411
- for (check in node['Service'][service]['Checks']) {
412
- checks.push(node['Service'][service]['Checks'][check]);
418
+ checks = [];
419
+ for (service in node['Service']) {
420
+ for (check in node['Service'][service]['Checks']) {
421
+ checks.push(node['Service'][service]['Checks'][check]);
422
+ }
413
423
  }
414
- }
415
- return checks;
424
+ return checks;
416
425
  }
417
426
 
418
427
  function getGeneralNodeStatus(nodeService) {
419
- status='passing';
420
- for (var serviceKey in nodeService) {
421
- switch(nodeState(nodeService[serviceKey]['Checks']){
422
- case 'passing': break;
423
- case 'warning': status='warning'; break;
424
- case 'critical': return 'critical'; break;
428
+ status = 'passing';
429
+
430
+ for (var serviceKey in nodeService) {
431
+ if (nodeService[serviceKey] != null && "Checks" in nodeService[serviceKey]) {
432
+ switch (nodeState(nodeService[serviceKey]['Checks']))  {
433
+ case 'passing':
434
+ break;
435
+ case 'warning':
436
+ status = 'warning';
437
+ break;
438
+ case 'critical':
439
+ return 'critical';
440
+ break;
441
+ }
442
+ }
425
443
  }
426
- }
427
- return status;
444
+ return status;
428
445
  }
429
446
 
430
447
  function updateStatusItem(statuses) {
431
- states = ['passing', 'warning', 'critical', 'total']
432
- for (state in states) {
433
- document.getElementById('service-status-' + states[state]).innerHTML = (statuses[states[state]] || 0);
434
- }
448
+ states = ['passing', 'warning', 'critical', 'total']
449
+ for (state in states) {
450
+ document.getElementById('service-status-' + states[state]).innerHTML = (statuses[states[state]] || 0);
451
+ }
435
452
  }
436
453
 
437
454
  function updateFilterDisplay(filterStatus) {
438
- $('.progress-status').each(function() {
439
- var status = $(this).attr('status');
440
- if (filterStatus == null || filterStatus == status) {
441
- $(this).removeClass('progress-deactivated');
442
- } else {
443
- $(this).addClass('progress-deactivated');
444
- }
445
- })
446
- $('.service-status').each(function() {
447
- var status = $(this).attr('status');
448
- if (filterStatus == null || filterStatus == status) {
449
- $(this).removeClass('status-deactivated');
455
+ $('.progress-status').each(function () {
456
+ var status = $(this).attr('status');
457
+ if (filterStatus == null || filterStatus == status) {
458
+ $(this).removeClass('progress-deactivated');
459
+ } else {
460
+ $(this).addClass('progress-deactivated');
461
+ }
462
+ })
463
+ $('.service-status').each(function () {
464
+ var status = $(this).attr('status');
465
+ if (filterStatus == null || filterStatus == status) {
466
+ $(this).removeClass('status-deactivated');
467
+ } else {
468
+ $(this).addClass('status-deactivated');
469
+ }
470
+ })
471
+
472
+ }
473
+
474
+ function updateURL(arg, value) {
475
+ var newUrl = new URL(location.href);
476
+ if (value == "" || value == null) {
477
+ newUrl.searchParams.delete(arg);
450
478
  } else {
451
- $(this).addClass('status-deactivated');
479
+ newUrl.searchParams.set(arg, value);
452
480
  }
453
- })
454
481
 
455
- }
482
+ window.history.pushState({}, "", newUrl);
483
+ }