diff --git a/ui-v2/app/controllers/dc/nodes/show.js b/ui-v2/app/controllers/dc/nodes/show.js index f90de0911380..3dc82775e6bd 100644 --- a/ui-v2/app/controllers/dc/nodes/show.js +++ b/ui-v2/app/controllers/dc/nodes/show.js @@ -1,9 +1,14 @@ import Controller from '@ember/controller'; import { inject as service } from '@ember/service'; import { get, set, computed } from '@ember/object'; +import { alias } from '@ember/object/computed'; import WithSearching from 'consul-ui/mixins/with-searching'; -export default Controller.extend(WithSearching, { +import WithEventSource, { listen } from 'consul-ui/mixins/with-event-source'; + +export default Controller.extend(WithEventSource, WithSearching, { dom: service('dom'), + notify: service('flashMessages'), + items: alias('item.Services'), queryParams: { s: { as: 'filter', @@ -16,6 +21,21 @@ export default Controller.extend(WithSearching, { }; this._super(...arguments); }, + item: listen('item').catch(function(e) { + if (e.target.readyState === 1) { + // OPEN + if (get(e, 'error.errors.firstObject.status') === '404') { + get(this, 'notify').add({ + destroyOnClick: false, + sticky: true, + type: 'warning', + action: 'update', + }); + get(this, 'tomography').close(); + get(this, 'sessions').close(); + } + } + }), searchable: computed('items', function() { return get(this, 'searchables.nodeservice') .add(get(this, 'items')) @@ -28,7 +48,7 @@ export default Controller.extend(WithSearching, { // This method is called immediately after `Route::setupController`, and done here rather than there // as this is a variable used purely for view level things, if the view was different we might not // need this variable - set(this, 'selectedTab', get(this.item, 'Checks.length') > 0 ? 'health-checks' : 'services'); + set(this, 'selectedTab', get(this, 'item.Checks.length') > 0 ? 'health-checks' : 'services'); }, actions: { change: function(e) { diff --git a/ui-v2/app/instance-initializers/event-source.js b/ui-v2/app/instance-initializers/event-source.js index 4c276424ff26..d2a707ee10c0 100644 --- a/ui-v2/app/instance-initializers/event-source.js +++ b/ui-v2/app/instance-initializers/event-source.js @@ -5,7 +5,7 @@ export function initialize(container) { if (config[enabled] || window.localStorage.getItem(enabled) !== null) { return; } - ['node', 'service', 'proxy'] + ['node', 'coordinate', 'session', 'service', 'proxy'] .map(function(item) { // create repositories that return a promise resolving to an EventSource return { @@ -20,7 +20,7 @@ export function initialize(container) { }) .concat([ // These are the routes where we overwrite the 'default' - // repo service. Default repos are repos that return a promise resovlving to + // repo service. Default repos are repos that return a promise resolving to // an ember-data record or recordset { route: 'dc/nodes/index', @@ -28,6 +28,14 @@ export function initialize(container) { repo: 'repository/node/event-source', }, }, + { + route: 'dc/nodes/show', + services: { + repo: 'repository/node/event-source', + coordinateRepo: 'repository/coordinate/event-source', + sessionRepo: 'repository/session/event-source', + }, + }, { route: 'dc/services/index', services: { diff --git a/ui-v2/app/models/node.js b/ui-v2/app/models/node.js index cbe4272a5869..be33ca7cf6b1 100644 --- a/ui-v2/app/models/node.js +++ b/ui-v2/app/models/node.js @@ -21,6 +21,7 @@ export default Model.extend({ Datacenter: attr('string'), Segment: attr(), Coord: attr(), + meta: attr(), hasStatus: function(status) { return hasStatus(get(this, 'Checks'), status); }, diff --git a/ui-v2/app/routes/dc/nodes/show.js b/ui-v2/app/routes/dc/nodes/show.js index 0449afc2df01..ad7bf3b029e0 100644 --- a/ui-v2/app/routes/dc/nodes/show.js +++ b/ui-v2/app/routes/dc/nodes/show.js @@ -1,17 +1,14 @@ import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; import { hash } from 'rsvp'; -import { get, set } from '@ember/object'; +import { get } from '@ember/object'; -import distance from 'consul-ui/utils/distance'; -import tomographyFactory from 'consul-ui/utils/tomography'; import WithBlockingActions from 'consul-ui/mixins/with-blocking-actions'; -const tomography = tomographyFactory(distance); - export default Route.extend(WithBlockingActions, { repo: service('repository/node'), sessionRepo: service('repository/session'), + coordinateRepo: service('repository/coordinate'), queryParams: { s: { as: 'filter', @@ -20,24 +17,11 @@ export default Route.extend(WithBlockingActions, { }, model: function(params) { const dc = this.modelFor('dc').dc.Name; - const repo = get(this, 'repo'); - const sessionRepo = get(this, 'sessionRepo'); + const name = params.name; return hash({ - item: repo.findBySlug(params.name, dc), - }).then(function(model) { - // TODO: Consider loading this after initial page load - const coordinates = get(model.item, 'Coordinates'); - return hash({ - ...model, - ...{ - tomography: - get(coordinates, 'length') > 1 - ? tomography(params.name, coordinates.map(item => get(item, 'data'))) - : null, - items: get(model.item, 'Services'), - sessions: sessionRepo.findByNode(get(model.item, 'Node'), dc), - }, - }); + item: get(this, 'repo').findBySlug(name, dc), + tomography: get(this, 'coordinateRepo').findAllByNode(name, dc), + sessions: get(this, 'sessionRepo').findByNode(name, dc), }); }, setupController: function(controller, model) { @@ -52,7 +36,9 @@ export default Route.extend(WithBlockingActions, { const node = get(item, 'Node'); return repo.remove(item).then(() => { return repo.findByNode(node, dc).then(function(sessions) { - set(controller, 'sessions', sessions); + controller.setProperties({ + sessions: sessions, + }); }); }); }, 'delete'); diff --git a/ui-v2/app/services/repository/coordinate.js b/ui-v2/app/services/repository/coordinate.js index f6f5c1d8e656..75b3f2f1f7dc 100644 --- a/ui-v2/app/services/repository/coordinate.js +++ b/ui-v2/app/services/repository/coordinate.js @@ -1,8 +1,23 @@ +import { get } from '@ember/object'; import RepositoryService from 'consul-ui/services/repository'; +import tomographyFactory from 'consul-ui/utils/tomography'; +import distance from 'consul-ui/utils/distance'; +const tomography = tomographyFactory(distance); + const modelName = 'coordinate'; export default RepositoryService.extend({ getModelName: function() { return modelName; }, + findAllByNode: function(node, dc, configuration) { + return this.findAllByDatacenter(dc, configuration).then(function(coordinates) { + let results = {}; + if (get(coordinates, 'length') > 1) { + results = tomography(node, coordinates.map(item => get(item, 'data'))); + } + results.meta = get(coordinates, 'meta'); + return results; + }); + }, }); diff --git a/ui-v2/app/services/repository/node.js b/ui-v2/app/services/repository/node.js index 0d7eb573446b..eec4f211d3eb 100644 --- a/ui-v2/app/services/repository/node.js +++ b/ui-v2/app/services/repository/node.js @@ -1,20 +1,9 @@ import RepositoryService from 'consul-ui/services/repository'; import { inject as service } from '@ember/service'; -import { get } from '@ember/object'; const modelName = 'node'; export default RepositoryService.extend({ coordinates: service('repository/coordinate'), getModelName: function() { return modelName; }, - findBySlug: function(slug, dc) { - return this._super(...arguments).then(node => { - return get(this, 'coordinates') - .findAllByDatacenter(dc) - .then(function(res) { - node.Coordinates = res; - return node; - }); - }); - }, }); diff --git a/ui-v2/app/templates/dc/nodes/-notifications.hbs b/ui-v2/app/templates/dc/nodes/-notifications.hbs index 70f90530b4cd..cbc36249f07c 100644 --- a/ui-v2/app/templates/dc/nodes/-notifications.hbs +++ b/ui-v2/app/templates/dc/nodes/-notifications.hbs @@ -4,5 +4,9 @@ {{else}} There was an error invalidating the session. {{/if}} +{{else if (eq type 'update')}} + {{#if (eq status 'warning') }} + This node no longer exists in the catalog. + {{else}} + {{/if}} {{/if}} - diff --git a/ui-v2/app/templates/dc/nodes/show.hbs b/ui-v2/app/templates/dc/nodes/show.hbs index 10a12fc576a8..3a4d135ffe6d 100644 --- a/ui-v2/app/templates/dc/nodes/show.hbs +++ b/ui-v2/app/templates/dc/nodes/show.hbs @@ -18,7 +18,7 @@ (array 'Health Checks' 'Services' - (if tomography 'Round Trip Time' '') + (if tomography.distances 'Round Trip Time' '') 'Lock Sessions' ) ) @@ -48,10 +48,10 @@ {{#each (compact (array - (hash id=(slugify 'Health Checks') partial='dc/nodes/healthchecks') - (hash id=(slugify 'Services') partial='dc/nodes/services') - (if tomography (hash id=(slugify 'Round Trip Time') partial='dc/nodes/rtt') '') - (hash id=(slugify 'Lock Sessions') partial='dc/nodes/sessions') + (hash id=(slugify 'Health Checks') partial='dc/nodes/healthchecks') + (hash id=(slugify 'Services') partial='dc/nodes/services') + (if tomography.distances (hash id=(slugify 'Round Trip Time') partial='dc/nodes/rtt') '') + (hash id=(slugify 'Lock Sessions') partial='dc/nodes/sessions') ) ) as |panel| }} diff --git a/ui-v2/tests/acceptance/dc/nodes/show.feature b/ui-v2/tests/acceptance/dc/nodes/show.feature index 2ea28bb3e22e..21ca13a9adf8 100644 --- a/ui-v2/tests/acceptance/dc/nodes/show.feature +++ b/ui-v2/tests/acceptance/dc/nodes/show.feature @@ -1,8 +1,9 @@ @setupApplicationTest Feature: dc / nodes / show: Show node - Scenario: Given 2 nodes all the tabs are visible and clickable + Background: Given 1 datacenter model with the value "dc1" - And 2 node models from yaml + Scenario: Given 2 nodes all the tabs are visible and clickable + Given 2 node models from yaml When I visit the node page for yaml --- dc: dc1 @@ -19,8 +20,7 @@ Feature: dc / nodes / show: Show node When I click lockSessions on the tabs And I see lockSessionsIsSelected on the tabs Scenario: Given 1 node all the tabs are visible and clickable and the RTT one isn't there - Given 1 datacenter model with the value "dc1" - And 1 node models from yaml + Given 1 node models from yaml --- ID: node-0 --- @@ -39,8 +39,7 @@ Feature: dc / nodes / show: Show node When I click lockSessions on the tabs And I see lockSessionsIsSelected on the tabs Scenario: Given 1 node with no checks all the tabs are visible but the Services tab is selected - Given 1 datacenter model with the value "dc1" - And 1 node models from yaml + Given 1 node models from yaml --- ID: node-0 Checks: [] @@ -55,3 +54,24 @@ Feature: dc / nodes / show: Show node And I see roundTripTime on the tabs And I see lockSessions on the tabs And I see servicesIsSelected on the tabs + Scenario: A node warns when deregistered whilst blocking + Given 1 node model from yaml + --- + ID: node-0 + --- + And settings from yaml + --- + consul:client: + blocking: 1 + throttle: 200 + --- + And a network latency of 100 + When I visit the node page for yaml + --- + dc: dc1 + node: node-0 + --- + Then the url should be /dc1/nodes/node-0 + And the url "/v1/internal/ui/node/node-0" responds with a 404 status + And pause until I see the text "no longer exists" in "[data-notification]" + diff --git a/ui-v2/tests/integration/services/repository/node-test.js b/ui-v2/tests/integration/services/repository/node-test.js index 8a6b4816da6a..d3086c04fc23 100644 --- a/ui-v2/tests/integration/services/repository/node-test.js +++ b/ui-v2/tests/integration/services/repository/node-test.js @@ -55,6 +55,10 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { return Object.assign({}, item, { Datacenter: dc, uid: `["${dc}","${item.ID}"]`, + meta: { + date: undefined, + cursor: undefined, + }, }); }) ); diff --git a/ui-v2/tests/unit/controllers/dc/nodes/show-test.js b/ui-v2/tests/unit/controllers/dc/nodes/show-test.js index a1dd0c5618c5..d6f93489b63d 100644 --- a/ui-v2/tests/unit/controllers/dc/nodes/show-test.js +++ b/ui-v2/tests/unit/controllers/dc/nodes/show-test.js @@ -2,7 +2,7 @@ import { moduleFor, test } from 'ember-qunit'; moduleFor('controller:dc/nodes/show', 'Unit | Controller | dc/nodes/show', { // Specify the other units that are required for this test. - needs: ['service:search', 'service:dom'], + needs: ['service:search', 'service:dom', 'service:flashMessages'], }); // Replace this with your real tests. diff --git a/ui-v2/tests/unit/routes/dc/nodes/show-test.js b/ui-v2/tests/unit/routes/dc/nodes/show-test.js index e6f486e6bc33..4f512ba9aa2c 100644 --- a/ui-v2/tests/unit/routes/dc/nodes/show-test.js +++ b/ui-v2/tests/unit/routes/dc/nodes/show-test.js @@ -4,6 +4,7 @@ moduleFor('route:dc/nodes/show', 'Unit | Route | dc/nodes/show', { // Specify the other units that are required for this test. needs: [ 'service:repository/node', + 'service:repository/coordinate', 'service:repository/session', 'service:feedback', 'service:logger',