diff --git a/ui-v2/app/models/coordinate.js b/ui-v2/app/models/coordinate.js index 7449c6c8713f..ae95ea1030ae 100644 --- a/ui-v2/app/models/coordinate.js +++ b/ui-v2/app/models/coordinate.js @@ -10,4 +10,5 @@ export default Model.extend({ Coord: attr(), Segment: attr('string'), Datacenter: attr('string'), + SyncTime: attr('number'), }); diff --git a/ui-v2/app/models/node.js b/ui-v2/app/models/node.js index be33ca7cf6b1..7c4de8a598d5 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(), + SyncTime: attr('number'), meta: attr(), hasStatus: function(status) { return hasStatus(get(this, 'Checks'), status); diff --git a/ui-v2/app/models/proxy.js b/ui-v2/app/models/proxy.js index bb28d6ac0881..cbd26bbc4fcd 100644 --- a/ui-v2/app/models/proxy.js +++ b/ui-v2/app/models/proxy.js @@ -10,4 +10,5 @@ export default Model.extend({ ServiceID: attr('string'), Node: attr('string'), ServiceProxy: attr(), + SyncTime: attr('number'), }); diff --git a/ui-v2/app/models/service.js b/ui-v2/app/models/service.js index 3d7e4259287e..0ce0696a6d2a 100644 --- a/ui-v2/app/models/service.js +++ b/ui-v2/app/models/service.js @@ -30,6 +30,7 @@ export default Model.extend({ Node: attr(), Service: attr(), Checks: attr(), + SyncTime: attr('number'), meta: attr(), passing: computed('ChecksPassing', 'Checks', function() { let num = 0; diff --git a/ui-v2/app/models/session.js b/ui-v2/app/models/session.js index d569c051bd91..c16f900b2432 100644 --- a/ui-v2/app/models/session.js +++ b/ui-v2/app/models/session.js @@ -20,4 +20,5 @@ export default Model.extend({ }, }), Datacenter: attr('string'), + SyncTime: attr('number'), }); diff --git a/ui-v2/app/serializers/application.js b/ui-v2/app/serializers/application.js index defe01efe81f..45a614f9e60f 100644 --- a/ui-v2/app/serializers/application.js +++ b/ui-v2/app/serializers/application.js @@ -1,6 +1,6 @@ import Serializer from 'ember-data/serializers/rest'; -import { get } from '@ember/object'; +import { set } from '@ember/object'; import { HEADERS_SYMBOL as HTTP_HEADERS_SYMBOL, HEADERS_INDEX as HTTP_HEADERS_INDEX, @@ -44,14 +44,17 @@ export default Serializer.extend({ requestType ); }, + timestamp: function() { + return new Date().getTime(); + }, normalizeMeta: function(store, primaryModelClass, headers, payload, id, requestType) { const meta = { cursor: headers[HTTP_HEADERS_INDEX], - date: headers['date'], }; if (requestType === 'query') { - meta.ids = payload.map(item => { - return get(item, this.primaryKey); + meta.date = this.timestamp(); + payload.forEach(function(item) { + set(item, 'SyncTime', meta.date); }); } return meta; diff --git a/ui-v2/app/services/repository/type/event-source.js b/ui-v2/app/services/repository/type/event-source.js index 7c4423835e18..31c1b41ea9b5 100644 --- a/ui-v2/app/services/repository/type/event-source.js +++ b/ui-v2/app/services/repository/type/event-source.js @@ -6,8 +6,27 @@ import LazyProxyService from 'consul-ui/services/lazy-proxy'; import { cache as createCache, BlockingEventSource } from 'consul-ui/utils/dom/event-source'; const createProxy = function(repo, find, settings, cache, serialize = JSON.stringify) { - // proxied find*..(id, dc) const client = get(this, 'client'); + const store = get(this, 'store'); + // custom createEvent, here used to reconcile the ember-data store for each tick + const createEvent = function(result, configuration) { + const event = { + type: 'message', + data: result, + }; + const meta = get(event.data || {}, 'meta'); + if (typeof meta.date !== 'undefined') { + // unload anything older than our current sync date/time + store.peekAll(repo.getModelName()).forEach(function(item) { + const date = get(item, 'SyncTime'); + if (typeof date !== 'undefined' && date != meta.date) { + store.unloadRecord(item); + } + }); + } + return event; + }; + // proxied find*..(id, dc) return function() { const key = `${repo.getModelName()}.${find}.${serialize([...arguments])}`; const _args = arguments; @@ -48,6 +67,7 @@ const createProxy = function(repo, find, settings, cache, serialize = JSON.strin settings: { enabled: settings.blocking, }, + createEvent: createEvent, } ); }; diff --git a/ui-v2/tests/integration/services/repository/coordinate-test.js b/ui-v2/tests/integration/services/repository/coordinate-test.js index 1c0f07f7f076..ff7d0994ceb6 100644 --- a/ui-v2/tests/integration/services/repository/coordinate-test.js +++ b/ui-v2/tests/integration/services/repository/coordinate-test.js @@ -1,13 +1,18 @@ import { moduleFor, test } from 'ember-qunit'; import repo from 'consul-ui/tests/helpers/repo'; +import { get } from '@ember/object'; const NAME = 'coordinate'; moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { // Specify the other units that are required for this test. - integration: true + integration: true, }); const dc = 'dc-1'; +const now = new Date().getTime(); test('findAllByDatacenter returns the correct data for list endpoint', function(assert) { + get(this.subject(), 'store').serializerFor(NAME).timestamp = function() { + return now; + }; return repo( 'Coordinate', 'findAllByDatacenter', @@ -26,6 +31,7 @@ test('findAllByDatacenter returns the correct data for list endpoint', function( expected(function(payload) { return payload.map(item => Object.assign({}, item, { + SyncTime: now, Datacenter: dc, uid: `["${dc}","${item.Node}"]`, }) diff --git a/ui-v2/tests/integration/services/repository/node-test.js b/ui-v2/tests/integration/services/repository/node-test.js index d3086c04fc23..af5e9ee397e4 100644 --- a/ui-v2/tests/integration/services/repository/node-test.js +++ b/ui-v2/tests/integration/services/repository/node-test.js @@ -1,5 +1,6 @@ import { moduleFor, test } from 'ember-qunit'; import repo from 'consul-ui/tests/helpers/repo'; +import { get } from '@ember/object'; const NAME = 'node'; moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { // Specify the other units that are required for this test. @@ -8,7 +9,11 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { const dc = 'dc-1'; const id = 'token-name'; +const now = new Date().getTime(); test('findByDatacenter returns the correct data for list endpoint', function(assert) { + get(this.subject(), 'store').serializerFor(NAME).timestamp = function() { + return now; + }; return repo( 'Node', 'findAllByDatacenter', @@ -27,6 +32,7 @@ test('findByDatacenter returns the correct data for list endpoint', function(ass expected(function(payload) { return payload.map(item => Object.assign({}, item, { + SyncTime: now, Datacenter: dc, uid: `["${dc}","${item.ID}"]`, }) @@ -56,7 +62,6 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { Datacenter: dc, uid: `["${dc}","${item.ID}"]`, meta: { - date: undefined, cursor: undefined, }, }); diff --git a/ui-v2/tests/integration/services/repository/service-test.js b/ui-v2/tests/integration/services/repository/service-test.js index cac6967922c4..ce5998b26dec 100644 --- a/ui-v2/tests/integration/services/repository/service-test.js +++ b/ui-v2/tests/integration/services/repository/service-test.js @@ -1,6 +1,7 @@ import { moduleFor, test } from 'ember-qunit'; import { skip } from 'qunit'; import repo from 'consul-ui/tests/helpers/repo'; +import { get } from '@ember/object'; const NAME = 'service'; moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { // Specify the other units that are required for this test. @@ -8,7 +9,11 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { }); const dc = 'dc-1'; const id = 'token-name'; +const now = new Date().getTime(); test('findByDatacenter returns the correct data for list endpoint', function(assert) { + get(this.subject(), 'store').serializerFor(NAME).timestamp = function() { + return now; + }; return repo( 'Service', 'findAllByDatacenter', @@ -27,6 +32,7 @@ test('findByDatacenter returns the correct data for list endpoint', function(ass expected(function(payload) { return payload.map(item => Object.assign({}, item, { + SyncTime: now, Datacenter: dc, uid: `["${dc}","${item.Name}"]`, }) @@ -69,7 +75,6 @@ test('findBySlug returns the correct data for item endpoint', function(assert) { service.Nodes = nodes; service.Tags = payload.Nodes[0].Service.Tags; service.meta = { - date: undefined, cursor: undefined, }; diff --git a/ui-v2/tests/integration/services/repository/session-test.js b/ui-v2/tests/integration/services/repository/session-test.js index cdc3fcc0a716..cbdb20849743 100644 --- a/ui-v2/tests/integration/services/repository/session-test.js +++ b/ui-v2/tests/integration/services/repository/session-test.js @@ -1,5 +1,6 @@ import { moduleFor, test } from 'ember-qunit'; import repo from 'consul-ui/tests/helpers/repo'; +import { get } from '@ember/object'; const NAME = 'session'; moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { // Specify the other units that are required for this test. @@ -8,7 +9,11 @@ moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { const dc = 'dc-1'; const id = 'node-name'; +const now = new Date().getTime(); test('findByNode returns the correct data for list endpoint', function(assert) { + get(this.subject(), 'store').serializerFor(NAME).timestamp = function() { + return now; + }; return repo( 'Session', 'findByNode', @@ -27,6 +32,7 @@ test('findByNode returns the correct data for list endpoint', function(assert) { expected(function(payload) { return payload.map(item => Object.assign({}, item, { + SyncTime: now, Datacenter: dc, uid: `["${dc}","${item.ID}"]`, })