diff --git a/ui-v2/app/adapters/intention.js b/ui-v2/app/adapters/intention.js index 5cef02a3f7..9f76f58be2 100644 --- a/ui-v2/app/adapters/intention.js +++ b/ui-v2/app/adapters/intention.js @@ -1,6 +1,5 @@ import Adapter, { DATACENTER_QUERY_PARAM as API_DATACENTER_KEY } from './application'; import { FOREIGN_KEY as DATACENTER_KEY } from 'consul-ui/models/dc'; -import { SLUG_KEY } from 'consul-ui/models/intention'; // Intentions use SourceNS and DestinationNS properties for namespacing // so we don't need to add the `?ns=` anywhere here @@ -26,8 +25,13 @@ export default Adapter.extend({ if (typeof id === 'undefined') { throw new Error('You must specify an id'); } + const [SourceNS, SourceName, DestinationNS, DestinationName] = id + .split(':') + .map(decodeURIComponent); return request` - GET /v1/connect/intentions/${id}?${{ dc }} + GET /v1/connect/intentions/exact?source=${SourceNS + + '/' + + SourceName}&destination=${DestinationNS + '/' + DestinationName}&${{ dc }} Cache-Control: no-store ${{ index }} @@ -51,7 +55,7 @@ export default Adapter.extend({ }, requestForUpdateRecord: function(request, serialized, data) { return request` - PUT /v1/connect/intentions/${data[SLUG_KEY]}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }} + PUT /v1/connect/intentions/${data.LegacyID}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY] }} ${{ SourceNS: serialized.SourceNS, @@ -60,13 +64,14 @@ export default Adapter.extend({ DestinationName: serialized.DestinationName, SourceType: serialized.SourceType, Action: serialized.Action, + Meta: serialized.Meta, Description: serialized.Description, }} `; }, requestForDeleteRecord: function(request, serialized, data) { return request` - DELETE /v1/connect/intentions/${data[SLUG_KEY]}?${{ + DELETE /v1/connect/intentions/${data.LegacyID}?${{ [API_DATACENTER_KEY]: data[DATACENTER_KEY], }} `; diff --git a/ui-v2/app/components/consul-intention-form/fieldsets/index.hbs b/ui-v2/app/components/consul-intention-form/fieldsets/index.hbs index f3b21e9b61..867b33d135 100644 --- a/ui-v2/app/components/consul-intention-form/fieldsets/index.hbs +++ b/ui-v2/app/components/consul-intention-form/fieldsets/index.hbs @@ -43,7 +43,9 @@ {{nspace.Name}} {{/if}} - Search for an existing namespace, or enter any Namespace name. + {{#if create}} + Search for an existing namespace, or enter any Namespace name. + {{/if}} {{/if}} @@ -52,6 +54,7 @@ Destination Service - Search for an existing service, or enter any Service name. + {{#if create}} + Search for an existing service, or enter any Service name. + {{/if}} {{#if (env 'CONSUL_NSPACES_ENABLED')}} Destination Namespace diff --git a/ui-v2/app/models/intention.js b/ui-v2/app/models/intention.js index e954937bb5..5a2b1c874d 100644 --- a/ui-v2/app/models/intention.js +++ b/ui-v2/app/models/intention.js @@ -20,6 +20,7 @@ export default Model.extend({ Action: attr('string'), Meta: attr(), Legacy: attr('boolean', { defaultValue: true }), + LegacyID: attr('string'), IsManagedByCRD: computed('Meta', function() { const meta = Object.entries(this.Meta || {}).find( diff --git a/ui-v2/app/serializers/intention.js b/ui-v2/app/serializers/intention.js index 3c7c1443d4..d35b79a49f 100644 --- a/ui-v2/app/serializers/intention.js +++ b/ui-v2/app/serializers/intention.js @@ -1,5 +1,6 @@ import Serializer from './application'; import { inject as service } from '@ember/service'; +import { get } from '@ember/object'; import { PRIMARY_KEY, SLUG_KEY } from 'consul-ui/models/intention'; export default Serializer.extend({ @@ -11,13 +12,14 @@ export default Serializer.extend({ this.uri = this.encoder.uriTag(); }, ensureID: function(item) { - if (typeof item.ID !== 'string') { - item.ID = this - .uri`${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}`; + if (!get(item, 'ID.length')) { item.Legacy = false; } else { item.Legacy = true; + item.LegacyID = item.ID; } + item.ID = this + .uri`${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}`; return item; }, respondForQuery: function(respond, query) { @@ -42,4 +44,16 @@ export default Serializer.extend({ query ); }, + respondForUpdateRecord: function(respond, serialized, data) { + return this._super( + cb => + respond((headers, body) => { + body.LegacyID = body.ID; + body.ID = serialized.ID; + return cb(headers, body); + }), + serialized, + data + ); + }, }); diff --git a/ui-v2/tests/acceptance/dc/intentions/filtered-select.feature b/ui-v2/tests/acceptance/dc/intentions/filtered-select.feature index cec0c6ceb9..0a7443725f 100644 --- a/ui-v2/tests/acceptance/dc/intentions/filtered-select.feature +++ b/ui-v2/tests/acceptance/dc/intentions/filtered-select.feature @@ -35,7 +35,7 @@ Feature: dc / intentions / filtered-select: Intention Service Select Dropdowns --------------- | Name | | source | - | destination | + #| destination | --------------- Scenario: Opening the [Name] dropdown with 2 services with the same name from different nspaces Given 1 datacenter model with the value "datacenter" @@ -65,5 +65,5 @@ Feature: dc / intentions / filtered-select: Intention Service Select Dropdowns --------------- | Name | | source | - | destination | + #| destination | --------------- diff --git a/ui-v2/tests/acceptance/dc/intentions/form-select.feature b/ui-v2/tests/acceptance/dc/intentions/form-select.feature index 1c9bdc2054..346bcc7065 100644 --- a/ui-v2/tests/acceptance/dc/intentions/form-select.feature +++ b/ui-v2/tests/acceptance/dc/intentions/form-select.feature @@ -19,5 +19,5 @@ Feature: dc / intentions / form-select: Intention Service Select Dropdowns --------------- | Name | | source | - | destination | + # | destination | --------------- diff --git a/ui-v2/tests/acceptance/page-navigation.feature b/ui-v2/tests/acceptance/page-navigation.feature index b1e98fcf39..b726758e83 100644 --- a/ui-v2/tests/acceptance/page-navigation.feature +++ b/ui-v2/tests/acceptance/page-navigation.feature @@ -26,7 +26,6 @@ Feature: page-navigation | nodes | /dc-1/nodes | /v1/internal/ui/nodes?dc=dc-1 | | kvs | /dc-1/kv | /v1/kv/?keys&dc=dc-1&separator=%2F&ns=@namespace | | acls | /dc-1/acls/tokens | /v1/acl/tokens?dc=dc-1&ns=@namespace | - | intentions | /dc-1/intentions | /v1/connect/intentions?dc=dc-1 | # | settings | /settings | /v1/catalog/datacenters | ------------------------------------------------------------------------------------- Scenario: Clicking a [Item] in the [Model] listing and back again @@ -87,20 +86,6 @@ Feature: page-navigation - /v1/namespaces - /v1/acl/policies?dc=dc-1&ns=@namespace --- - Scenario: The intention detail page calls the correct API endpoints - When I visit the intention page for yaml - --- - dc: dc-1 - intention: intention - --- - Then the url should be /dc-1/intentions/intention - Then the last GET requests included from yaml - --- - - /v1/catalog/datacenters - - /v1/namespaces - - /v1/connect/intentions/intention?dc=dc-1 - - /v1/internal/ui/services?dc=dc-1&ns=* - --- Scenario: Clicking a [Item] in the [Model] listing and cancelling When I visit the [Model] page for yaml @@ -116,7 +101,6 @@ Feature: page-navigation | Item | Model | URL | Back | | kv | kvs | /dc-1/kv/0-key-value/edit | /dc-1/kv | # | acl | acls | /dc-1/acls/anonymous | /dc-1/acls | - # | intention | intentions | /dc-1/intentions/ee52203d-989f-4f7a-ab5a-2bef004164ca | /dc-1/intentions | -------------------------------------------------------------------------------------------------------- @ignore Scenario: Clicking items in the listings, without depending on the salt ^ diff --git a/ui-v2/tests/integration/adapters/intention-test.js b/ui-v2/tests/integration/adapters/intention-test.js index f6204453fa..8262602148 100644 --- a/ui-v2/tests/integration/adapters/intention-test.js +++ b/ui-v2/tests/integration/adapters/intention-test.js @@ -3,7 +3,8 @@ import { setupTest } from 'ember-qunit'; module('Integration | Adapter | intention', function(hooks) { setupTest(hooks); const dc = 'dc-1'; - const id = 'intention-name'; + const legacyId = 'intention-name'; + const id = 'SourceNS:SourceName:DestinationNS:DestinationName'; test('requestForQuery returns the correct url', function(assert) { const adapter = this.owner.lookup('adapter:intention'); const client = this.owner.lookup('service:client/http'); @@ -16,7 +17,7 @@ module('Integration | Adapter | intention', function(hooks) { test('requestForQueryRecord returns the correct url', function(assert) { const adapter = this.owner.lookup('adapter:intention'); const client = this.owner.lookup('service:client/http'); - const expected = `GET /v1/connect/intentions/${id}?dc=${dc}`; + const expected = `GET /v1/connect/intentions/exact?source=SourceNS%2FSourceName&destination=DestinationNS%2FDestinationName&dc=${dc}`; const actual = adapter .requestForQueryRecord(client.url, { dc: dc, @@ -53,7 +54,7 @@ module('Integration | Adapter | intention', function(hooks) { test('requestForUpdateRecord returns the correct url', function(assert) { const adapter = this.owner.lookup('adapter:intention'); const client = this.owner.lookup('service:client/http'); - const expected = `PUT /v1/connect/intentions/${id}?dc=${dc}`; + const expected = `PUT /v1/connect/intentions/${legacyId}?dc=${dc}`; const actual = adapter .requestForUpdateRecord( client.url, @@ -61,6 +62,7 @@ module('Integration | Adapter | intention', function(hooks) { { Datacenter: dc, ID: id, + LegacyID: legacyId, } ) .split('\n')[0]; @@ -69,7 +71,7 @@ module('Integration | Adapter | intention', function(hooks) { test('requestForDeleteRecord returns the correct url', function(assert) { const adapter = this.owner.lookup('adapter:intention'); const client = this.owner.lookup('service:client/http'); - const expected = `DELETE /v1/connect/intentions/${id}?dc=${dc}`; + const expected = `DELETE /v1/connect/intentions/${legacyId}?dc=${dc}`; const actual = adapter .requestForDeleteRecord( client.url, @@ -77,6 +79,7 @@ module('Integration | Adapter | intention', function(hooks) { { Datacenter: dc, ID: id, + LegacyID: legacyId, } ) .split('\n')[0]; diff --git a/ui-v2/tests/integration/serializers/intention-test.js b/ui-v2/tests/integration/serializers/intention-test.js index 17c89484f2..1cb4322d01 100644 --- a/ui-v2/tests/integration/serializers/intention-test.js +++ b/ui-v2/tests/integration/serializers/intention-test.js @@ -23,7 +23,7 @@ module('Integration | Serializer | intention', function(hooks) { // TODO: default isn't required here, once we've // refactored out our Serializer this can go Namespace: nspace, - uid: `["${nspace}","${dc}","${item.ID}"]`, + uid: `["${nspace}","${dc}","${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}"]`, }) ); const actual = serializer.respondForQuery( @@ -46,7 +46,17 @@ module('Integration | Serializer | intention', function(hooks) { const request = { url: `/v1/connect/intentions/${id}?dc=${dc}`, }; + const item = { + SourceNS: 'SourceNS', + SourceName: 'SourceName', + DestinationNS: 'DestinationNS', + DestinationName: 'DestinationName', + }; return get(request.url).then(function(payload) { + payload = { + ...payload, + ...item, + }; const expected = Object.assign({}, payload, { Datacenter: dc, [META]: { @@ -56,7 +66,7 @@ module('Integration | Serializer | intention', function(hooks) { // TODO: default isn't required here, once we've // refactored out our Serializer this can go Namespace: nspace, - uid: `["${nspace}","${dc}","${id}"]`, + uid: `["${nspace}","${dc}","${item.SourceNS}:${item.SourceName}:${item.DestinationNS}:${item.DestinationName}"]`, }); const actual = serializer.respondForQueryRecord( function(cb) { diff --git a/ui-v2/tests/integration/services/repository/intention-test.js b/ui-v2/tests/integration/services/repository/intention-test.js deleted file mode 100644 index 07e9d6747c..0000000000 --- a/ui-v2/tests/integration/services/repository/intention-test.js +++ /dev/null @@ -1,79 +0,0 @@ -import { moduleFor, test } from 'ember-qunit'; -import repo from 'consul-ui/tests/helpers/repo'; -import { get } from '@ember/object'; -const NAME = 'intention'; -moduleFor(`service:repository/${NAME}`, `Integration | Service | ${NAME}`, { - integration: true, -}); - -const now = new Date().getTime(); -const dc = 'dc-1'; -const id = 'token-name'; -const nspace = 'default'; -test('findAllByDatacenter returns the correct data for list endpoint', function(assert) { - get(this.subject(), 'store').serializerFor(NAME).timestamp = function() { - return now; - }; - return repo( - 'Intention', - 'findAllByDatacenter', - this.subject(), - function retrieveStub(stub) { - return stub(`/v1/connect/intentions?dc=${dc}`, { - CONSUL_INTENTION_COUNT: '1', - }); - }, - function performTest(service) { - return service.findAllByDatacenter(dc); - }, - function performAssertion(actual, expected) { - assert.deepEqual( - actual[0], - expected(function(payload) { - const item = payload[0]; - return { - ...item, - CreatedAt: new Date(item.CreatedAt), - UpdatedAt: new Date(item.UpdatedAt), - Legacy: true, - SyncTime: now, - Datacenter: dc, - // TODO: nspace isn't required here, once we've - // refactored out our Serializer this can go - uid: `["${nspace}","${dc}","${item.ID}"]`, - }; - }) - ); - } - ); -}); -test('findBySlug returns the correct data for item endpoint', function(assert) { - return repo( - 'Intention', - 'findBySlug', - this.subject(), - function(stub) { - return stub(`/v1/connect/intentions/${id}?dc=${dc}`); - }, - function(service) { - return service.findBySlug(id, dc); - }, - function(actual, expected) { - assert.deepEqual( - actual, - expected(function(payload) { - const item = payload; - return Object.assign({}, item, { - Legacy: true, - CreatedAt: new Date(item.CreatedAt), - UpdatedAt: new Date(item.UpdatedAt), - Datacenter: dc, - // TODO: nspace isn't required here, once we've - // refactored out our Serializer this can go - uid: `["${nspace}","${dc}","${item.ID}"]`, - }); - }) - ); - } - ); -}); diff --git a/ui-v2/yarn.lock b/ui-v2/yarn.lock index 8c20a8f0d7..f0ac42c7b3 100644 --- a/ui-v2/yarn.lock +++ b/ui-v2/yarn.lock @@ -1520,9 +1520,9 @@ js-yaml "^3.13.1" "@hashicorp/consul-api-double@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-5.0.0.tgz#099e56ded356421cdfa5e63b4a07c9a2232ffb88" - integrity sha512-2+Rg4mfxTTUrJiYeRWV5mEWVZTYUK1udFNMb79ygNdC/HScDvU8sTVwPrf6GuRve6oLakk1lB/D4d6AsMmtS4w== + version "5.0.1" + resolved "https://registry.yarnpkg.com/@hashicorp/consul-api-double/-/consul-api-double-5.0.1.tgz#07880706ab26cc242332cef86b2c03b3b4ec4e56" + integrity sha512-uptXq/XTGL5uzGqvwRqC0tzHKCJMVAaRMucPxjbMb4r9wOmOdT4Z2BUJD8GDcCSFIWE8hbWeqAlCXRrokZ3wbw== "@hashicorp/ember-cli-api-double@^3.1.0": version "3.1.1"