2014-04-25 17:49:36 +00:00
|
|
|
//
|
|
|
|
// A Consul service.
|
|
|
|
//
|
|
|
|
App.Service = Ember.Object.extend({
|
|
|
|
//
|
|
|
|
// The number of failing checks within the service.
|
|
|
|
//
|
|
|
|
failingChecks: function() {
|
2014-04-30 21:31:40 +00:00
|
|
|
// If the service was returned from `/v1/internal/ui/services`
|
|
|
|
// then we have a aggregated value which we can just grab
|
2014-08-21 18:31:58 +00:00
|
|
|
if (this.get('ChecksCritical') !== undefined) {
|
|
|
|
return (this.get('ChecksCritical') + this.get('ChecksWarning'));
|
2014-04-30 21:31:40 +00:00
|
|
|
// Otherwise, we need to filter the child checks by both failing
|
|
|
|
// states
|
2014-04-30 18:02:20 +00:00
|
|
|
} else {
|
2014-06-03 17:53:22 +00:00
|
|
|
var checks = this.get('Checks');
|
|
|
|
return (checks.filterBy('Status', 'critical').get('length') +
|
2014-08-21 18:31:58 +00:00
|
|
|
checks.filterBy('Status', 'warning').get('length'));
|
2014-04-30 18:02:20 +00:00
|
|
|
}
|
2014-04-29 19:24:32 +00:00
|
|
|
}.property('Checks'),
|
2014-04-25 17:49:36 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// The number of passing checks within the service.
|
|
|
|
//
|
|
|
|
passingChecks: function() {
|
2014-04-30 21:31:40 +00:00
|
|
|
// If the service was returned from `/v1/internal/ui/services`
|
|
|
|
// then we have a aggregated value which we can just grab
|
2014-08-21 18:31:58 +00:00
|
|
|
if (this.get('ChecksPassing') !== undefined) {
|
|
|
|
return this.get('ChecksPassing');
|
2014-04-30 21:31:40 +00:00
|
|
|
// Otherwise, we need to filter the child checks by both failing
|
|
|
|
// states
|
2014-04-30 18:02:20 +00:00
|
|
|
} else {
|
|
|
|
return this.get('Checks').filterBy('Status', 'passing').get('length');
|
|
|
|
}
|
2014-04-29 19:24:32 +00:00
|
|
|
}.property('Checks'),
|
2014-04-25 17:49:36 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// The formatted message returned for the user which represents the
|
|
|
|
// number of checks failing or passing. Returns `1 passing` or `2 failing`
|
|
|
|
//
|
|
|
|
checkMessage: function() {
|
|
|
|
if (this.get('hasFailingChecks') === false) {
|
|
|
|
return this.get('passingChecks') + ' passing';
|
|
|
|
} else {
|
|
|
|
return this.get('failingChecks') + ' failing';
|
|
|
|
}
|
2014-04-29 19:24:32 +00:00
|
|
|
}.property('Checks'),
|
2014-04-25 17:49:36 +00:00
|
|
|
|
2014-06-04 19:44:17 +00:00
|
|
|
nodes: function() {
|
2014-08-21 18:31:58 +00:00
|
|
|
return (this.get('Nodes'));
|
2014-06-04 19:44:17 +00:00
|
|
|
}.property('Nodes'),
|
|
|
|
|
2014-04-25 17:49:36 +00:00
|
|
|
//
|
|
|
|
// Boolean of whether or not there are failing checks in the service.
|
|
|
|
// This is used to set color backgrounds and so on.
|
|
|
|
//
|
2015-10-26 01:21:50 +00:00
|
|
|
hasFailingChecks: Ember.computed.gt('failingChecks', 0),
|
2014-06-02 14:35:46 +00:00
|
|
|
|
2014-06-03 17:53:22 +00:00
|
|
|
//
|
|
|
|
// Key used for filtering through an array of this model, i.e s
|
|
|
|
// searching
|
|
|
|
//
|
2015-10-26 01:21:50 +00:00
|
|
|
filterKey: Ember.computed.alias('Name'),
|
2014-04-25 17:49:36 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
//
|
|
|
|
// A Consul Node
|
|
|
|
//
|
|
|
|
App.Node = Ember.Object.extend({
|
|
|
|
//
|
|
|
|
// The number of failing checks within the service.
|
|
|
|
//
|
|
|
|
failingChecks: function() {
|
2015-10-26 01:21:50 +00:00
|
|
|
return this.get('Checks').reduce(function(sum, check) {
|
|
|
|
var status = Ember.get(check, 'Status');
|
|
|
|
// We view both warning and critical as failing
|
|
|
|
return (status === 'critical' || status === 'warning') ?
|
|
|
|
sum + 1 :
|
|
|
|
sum;
|
|
|
|
}, 0);
|
2014-04-29 19:30:00 +00:00
|
|
|
}.property('Checks'),
|
2014-04-25 17:49:36 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// The number of passing checks within the service.
|
|
|
|
//
|
|
|
|
passingChecks: function() {
|
|
|
|
return this.get('Checks').filterBy('Status', 'passing').get('length');
|
2014-04-29 19:24:32 +00:00
|
|
|
}.property('Checks'),
|
2014-04-25 17:49:36 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// The formatted message returned for the user which represents the
|
|
|
|
// number of checks failing or passing. Returns `1 passing` or `2 failing`
|
|
|
|
//
|
|
|
|
checkMessage: function() {
|
|
|
|
if (this.get('hasFailingChecks') === false) {
|
|
|
|
return this.get('passingChecks') + ' passing';
|
|
|
|
} else {
|
|
|
|
return this.get('failingChecks') + ' failing';
|
|
|
|
}
|
2014-04-29 19:24:32 +00:00
|
|
|
}.property('Checks'),
|
2014-04-25 17:49:36 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Boolean of whether or not there are failing checks in the service.
|
|
|
|
// This is used to set color backgrounds and so on.
|
|
|
|
//
|
2015-10-26 01:21:50 +00:00
|
|
|
hasFailingChecks: Ember.computed.gt('failingChecks', 0),
|
2014-06-02 14:35:46 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// The number of services on the node
|
|
|
|
//
|
2015-10-26 01:21:50 +00:00
|
|
|
numServices: Ember.computed.alias('Services.length'),
|
2014-06-04 19:44:17 +00:00
|
|
|
|
2015-10-26 01:21:50 +00:00
|
|
|
services: Ember.computed.alias('Services'),
|
2014-06-02 14:35:46 +00:00
|
|
|
|
2015-10-26 01:21:50 +00:00
|
|
|
filterKey: Ember.computed.alias('Node')
|
2014-04-25 17:49:36 +00:00
|
|
|
});
|
|
|
|
|
2014-04-29 17:06:26 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// A key/value object
|
|
|
|
//
|
2014-04-30 14:09:41 +00:00
|
|
|
App.Key = Ember.Object.extend(Ember.Validations.Mixin, {
|
2018-03-19 16:56:00 +00:00
|
|
|
// Validates using the Ember.Validations library
|
2014-04-30 14:09:41 +00:00
|
|
|
validations: {
|
2014-04-30 23:22:07 +00:00
|
|
|
Key: { presence: true }
|
2014-04-30 14:09:41 +00:00
|
|
|
},
|
|
|
|
|
2017-02-06 14:32:37 +00:00
|
|
|
// Boolean if field should validate JSON
|
|
|
|
validateJson: false,
|
2014-04-30 21:31:40 +00:00
|
|
|
// Boolean if the key is valid
|
2014-04-30 19:02:31 +00:00
|
|
|
keyValid: Ember.computed.empty('errors.Key'),
|
2014-04-30 21:31:40 +00:00
|
|
|
// Boolean if the value is valid
|
2014-04-30 19:02:31 +00:00
|
|
|
valueValid: Ember.computed.empty('errors.Value'),
|
|
|
|
|
2017-12-21 01:40:47 +00:00
|
|
|
// Escape any user-entered parts that aren't URL-safe, but put slashes back since
|
|
|
|
// they are common in keys, and the UI lets users make "folders" by simply adding
|
|
|
|
// them to keys.
|
2017-12-20 18:19:50 +00:00
|
|
|
Key: function(key, value) {
|
|
|
|
// setter
|
|
|
|
if (arguments.length > 1) {
|
2017-12-21 01:40:47 +00:00
|
|
|
clean = value
|
|
|
|
try {
|
|
|
|
clean = decodeURIComponent(clean);
|
|
|
|
} catch (e) {
|
|
|
|
// If they've got something that's not valid URL syntax then keep going;
|
|
|
|
// this means that at worst we might end up double escaping some things.
|
|
|
|
}
|
|
|
|
clean = encodeURIComponent(clean).replace(/%2F/g, "/")
|
2017-12-20 18:19:50 +00:00
|
|
|
this.set('cleanKey', clean);
|
|
|
|
return clean;
|
|
|
|
}
|
|
|
|
|
|
|
|
// getter
|
|
|
|
return this.get('cleanKey')
|
|
|
|
}.property('Key'),
|
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// The key with the parent removed.
|
|
|
|
// This is only for display purposes, and used for
|
|
|
|
// showing the key name inside of a nested key.
|
2014-04-30 19:02:31 +00:00
|
|
|
keyWithoutParent: function() {
|
|
|
|
return (this.get('Key').replace(this.get('parentKey'), ''));
|
|
|
|
}.property('Key'),
|
2014-04-30 16:15:54 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// Boolean if the key is a "folder" or not, i.e is a nested key
|
|
|
|
// that feels like a folder. Used for UI
|
2014-04-29 17:06:26 +00:00
|
|
|
isFolder: function() {
|
2014-04-30 23:22:07 +00:00
|
|
|
if (this.get('Key') === undefined) {
|
|
|
|
return false;
|
2014-08-21 18:31:58 +00:00
|
|
|
}
|
|
|
|
return (this.get('Key').slice(-1) === '/');
|
2014-04-30 20:30:14 +00:00
|
|
|
}.property('Key'),
|
|
|
|
|
2014-06-06 16:21:36 +00:00
|
|
|
// Boolean if the key is locked or now
|
|
|
|
isLocked: function() {
|
|
|
|
if (!this.get('Session')) {
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}.property('Session'),
|
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// Determines what route to link to. If it's a folder,
|
|
|
|
// it will link to kv.show. Otherwise, kv.edit
|
2014-04-29 20:32:38 +00:00
|
|
|
linkToRoute: function() {
|
2014-05-04 21:05:00 +00:00
|
|
|
if (this.get('Key').slice(-1) === '/') {
|
2014-08-21 18:31:58 +00:00
|
|
|
return 'kv.show';
|
2014-04-29 20:32:38 +00:00
|
|
|
} else {
|
2014-08-21 18:31:58 +00:00
|
|
|
return 'kv.edit';
|
2014-04-29 20:32:38 +00:00
|
|
|
}
|
2014-04-30 19:02:31 +00:00
|
|
|
}.property('Key'),
|
2014-04-29 20:32:38 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// The base64 decoded value of the key.
|
|
|
|
// if you set on this key, it will update
|
|
|
|
// the key.Value
|
2014-04-30 20:30:14 +00:00
|
|
|
valueDecoded: function(key, value) {
|
2014-04-30 21:31:40 +00:00
|
|
|
|
|
|
|
// setter
|
2014-04-30 20:30:14 +00:00
|
|
|
if (arguments.length > 1) {
|
2014-04-30 21:31:40 +00:00
|
|
|
this.set('Value', value);
|
2014-04-30 22:31:45 +00:00
|
|
|
return value;
|
2014-04-30 20:30:14 +00:00
|
|
|
}
|
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// getter
|
|
|
|
|
|
|
|
// If the value is null, we don't
|
|
|
|
// want to try and base64 decode it, so just return
|
2014-04-30 20:30:14 +00:00
|
|
|
if (this.get('Value') === null) {
|
|
|
|
return "";
|
|
|
|
}
|
2015-07-23 07:56:23 +00:00
|
|
|
if (Base64.extendString) {
|
|
|
|
// you have to explicitly extend String.prototype
|
|
|
|
Base64.extendString();
|
|
|
|
}
|
2014-04-30 21:31:40 +00:00
|
|
|
// base64 decode the value
|
2015-07-23 06:47:32 +00:00
|
|
|
return (this.get('Value').fromBase64());
|
2014-04-30 20:30:14 +00:00
|
|
|
}.property('Value'),
|
|
|
|
|
2017-02-06 14:32:37 +00:00
|
|
|
// Check if JSON is valid by attempting a native JSON parse
|
|
|
|
isValidJson: function() {
|
2017-02-06 15:08:44 +00:00
|
|
|
var value;
|
|
|
|
|
|
|
|
try {
|
|
|
|
window.atob(this.get('Value'));
|
|
|
|
value = this.get('valueDecoded');
|
|
|
|
} catch (e) {
|
|
|
|
value = this.get('Value');
|
|
|
|
}
|
|
|
|
|
2017-02-06 14:32:37 +00:00
|
|
|
try {
|
2017-02-06 15:08:44 +00:00
|
|
|
JSON.parse(value);
|
2017-02-06 14:32:37 +00:00
|
|
|
return true;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}.property('Value'),
|
2014-04-30 21:31:40 +00:00
|
|
|
|
|
|
|
// An array of the key broken up by the /
|
2014-04-29 18:49:07 +00:00
|
|
|
keyParts: function() {
|
2014-04-30 19:02:31 +00:00
|
|
|
var key = this.get('Key');
|
2014-04-29 17:34:13 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// If the key is a folder, remove the last
|
|
|
|
// slash to split properly
|
2014-04-29 18:49:07 +00:00
|
|
|
if (key.slice(-1) == "/") {
|
|
|
|
key = key.substring(0, key.length - 1);
|
|
|
|
}
|
2014-04-30 21:31:40 +00:00
|
|
|
|
2014-04-29 18:49:07 +00:00
|
|
|
return key.split('/');
|
2014-04-30 19:02:31 +00:00
|
|
|
}.property('Key'),
|
2014-04-29 18:49:07 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// The parent Key is the key one level above this.Key
|
|
|
|
// key: baz/bar/foobar/
|
|
|
|
// grandParent: baz/bar/
|
2014-04-29 18:49:07 +00:00
|
|
|
parentKey: function() {
|
2014-04-29 19:24:32 +00:00
|
|
|
var parts = this.get('keyParts').toArray();
|
2014-04-29 18:49:07 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// Remove the last item, essentially going up a level
|
2018-03-19 16:56:00 +00:00
|
|
|
// in hierarchy
|
2014-04-29 18:49:07 +00:00
|
|
|
parts.pop();
|
|
|
|
|
|
|
|
return parts.join("/") + "/";
|
2014-04-30 19:02:31 +00:00
|
|
|
}.property('Key'),
|
2014-04-29 18:49:07 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// The grandParent Key is the key two levels above this.Key
|
|
|
|
// key: baz/bar/foobar/
|
|
|
|
// grandParent: baz/
|
2014-04-29 18:49:07 +00:00
|
|
|
grandParentKey: function() {
|
2014-04-29 19:24:32 +00:00
|
|
|
var parts = this.get('keyParts').toArray();
|
2014-04-29 17:34:13 +00:00
|
|
|
|
2014-04-30 21:31:40 +00:00
|
|
|
// Remove the last two items, jumping two levels back
|
2014-04-29 18:49:07 +00:00
|
|
|
parts.pop();
|
|
|
|
parts.pop();
|
2014-04-29 17:06:26 +00:00
|
|
|
|
2014-04-29 18:49:07 +00:00
|
|
|
return parts.join("/") + "/";
|
2014-04-30 19:02:31 +00:00
|
|
|
}.property('Key')
|
2014-04-29 17:06:26 +00:00
|
|
|
});
|
2014-08-21 21:44:17 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// An ACL
|
|
|
|
//
|
|
|
|
App.Acl = Ember.Object.extend({
|
2014-08-22 19:25:10 +00:00
|
|
|
isNotAnon: function() {
|
|
|
|
if (this.get('ID') === "anonymous"){
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}.property('ID')
|
|
|
|
});
|
|
|
|
|
|
|
|
// Wrap localstorage with an ember object
|
|
|
|
App.Settings = Ember.Object.extend({
|
|
|
|
unknownProperty: function(key) {
|
|
|
|
return localStorage[key];
|
|
|
|
},
|
|
|
|
|
|
|
|
setUnknownProperty: function(key, value) {
|
|
|
|
if(Ember.isNone(value)) {
|
|
|
|
delete localStorage[key];
|
|
|
|
} else {
|
|
|
|
localStorage[key] = value;
|
|
|
|
}
|
|
|
|
this.notifyPropertyChange(key);
|
|
|
|
return value;
|
|
|
|
},
|
|
|
|
|
|
|
|
clear: function() {
|
|
|
|
this.beginPropertyChanges();
|
|
|
|
for (var i=0, l=localStorage.length; i<l; i++){
|
|
|
|
this.set(localStorage.key(i));
|
|
|
|
}
|
|
|
|
localStorage.clear();
|
|
|
|
this.endPropertyChanges();
|
|
|
|
}
|
2014-08-21 21:44:17 +00:00
|
|
|
});
|