// // A Consul service. // App.Service = Ember.Object.extend({ // // The number of failing checks within the service. // failingChecks: function() { // If the service was returned from `/v1/internal/ui/services` // then we have a aggregated value which we can just grab if (this.get('ChecksCritical') !== undefined) { return (this.get('ChecksCritical') + this.get('ChecksWarning')); // Otherwise, we need to filter the child checks by both failing // states } else { var checks = this.get('Checks'); return (checks.filterBy('Status', 'critical').get('length') + checks.filterBy('Status', 'warning').get('length')); } }.property('Checks'), // // The number of passing checks within the service. // passingChecks: function() { // If the service was returned from `/v1/internal/ui/services` // then we have a aggregated value which we can just grab if (this.get('ChecksPassing') !== undefined) { return this.get('ChecksPassing'); // Otherwise, we need to filter the child checks by both failing // states } else { return this.get('Checks').filterBy('Status', 'passing').get('length'); } }.property('Checks'), // // 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'; } }.property('Checks'), nodes: function() { return (this.get('Nodes')); }.property('Nodes'), // // Boolean of whether or not there are failing checks in the service. // This is used to set color backgrounds and so on. // hasFailingChecks: Ember.computed.gt('failingChecks', 0), // // Key used for filtering through an array of this model, i.e s // searching // filterKey: Ember.computed.alias('Name'), }); // // A Consul Node // App.Node = Ember.Object.extend({ // // The number of failing checks within the service. // failingChecks: function() { 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); }.property('Checks'), // // The number of passing checks within the service. // passingChecks: function() { return this.get('Checks').filterBy('Status', 'passing').get('length'); }.property('Checks'), // // 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'; } }.property('Checks'), // // Boolean of whether or not there are failing checks in the service. // This is used to set color backgrounds and so on. // hasFailingChecks: Ember.computed.gt('failingChecks', 0), // // The number of services on the node // numServices: Ember.computed.alias('Services.length'), services: Ember.computed.alias('Services'), filterKey: Ember.computed.alias('Node') }); // // A key/value object // App.Key = Ember.Object.extend(Ember.Validations.Mixin, { // Validates using the Ember.Validations library validations: { Key: { presence: true } }, // Boolean if field should validate JSON validateJson: false, // Boolean if the key is valid keyValid: Ember.computed.empty('errors.Key'), // Boolean if the value is valid valueValid: Ember.computed.empty('errors.Value'), // 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. Key: function(key, value) { // setter if (arguments.length > 1) { 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, "/") this.set('cleanKey', clean); return clean; } // getter return this.get('cleanKey') }.property('Key'), // The key with the parent removed. // This is only for display purposes, and used for // showing the key name inside of a nested key. keyWithoutParent: function() { return (this.get('Key').replace(this.get('parentKey'), '')); }.property('Key'), // Boolean if the key is a "folder" or not, i.e is a nested key // that feels like a folder. Used for UI isFolder: function() { if (this.get('Key') === undefined) { return false; } return (this.get('Key').slice(-1) === '/'); }.property('Key'), // Boolean if the key is locked or now isLocked: function() { if (!this.get('Session')) { return false; } else { return true; } }.property('Session'), // Determines what route to link to. If it's a folder, // it will link to kv.show. Otherwise, kv.edit linkToRoute: function() { if (this.get('Key').slice(-1) === '/') { return 'kv.show'; } else { return 'kv.edit'; } }.property('Key'), // The base64 decoded value of the key. // if you set on this key, it will update // the key.Value valueDecoded: function(key, value) { // setter if (arguments.length > 1) { this.set('Value', value); return value; } // getter // If the value is null, we don't // want to try and base64 decode it, so just return if (this.get('Value') === null) { return ""; } if (Base64.extendString) { // you have to explicitly extend String.prototype Base64.extendString(); } // base64 decode the value return (this.get('Value').fromBase64()); }.property('Value'), // Check if JSON is valid by attempting a native JSON parse isValidJson: function() { var value; try { window.atob(this.get('Value')); value = this.get('valueDecoded'); } catch (e) { value = this.get('Value'); } try { JSON.parse(value); return true; } catch (e) { return false; } }.property('Value'), // An array of the key broken up by the / keyParts: function() { var key = this.get('Key'); // If the key is a folder, remove the last // slash to split properly if (key.slice(-1) == "/") { key = key.substring(0, key.length - 1); } return key.split('/'); }.property('Key'), // The parent Key is the key one level above this.Key // key: baz/bar/foobar/ // grandParent: baz/bar/ parentKey: function() { var parts = this.get('keyParts').toArray(); // Remove the last item, essentially going up a level // in hierarchy parts.pop(); return parts.join("/") + "/"; }.property('Key'), // The grandParent Key is the key two levels above this.Key // key: baz/bar/foobar/ // grandParent: baz/ grandParentKey: function() { var parts = this.get('keyParts').toArray(); // Remove the last two items, jumping two levels back parts.pop(); parts.pop(); return parts.join("/") + "/"; }.property('Key') }); // // An ACL // App.Acl = Ember.Object.extend({ 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