From c20cff9bf5ca2899974f958bbb1b5bfa42deebee Mon Sep 17 00:00:00 2001 From: John Cowen Date: Wed, 1 Apr 2020 09:55:49 +0100 Subject: [PATCH] ui: Moves intentions listing and form into components (#7549) Whilst we tried to do this with the smallest amount of changes possible, our acceptance tests for trying to submit a blank form started failing due to usage of `destroyRecord`, its seems that the correct way to achieve the same thing is to use `rollbackAttributes` instead. We changed that here and the tests pass once again. Furture work related to this will involve change the rest of the UI where we use `destroyRecord` to achieve the same thing, to use `rollbackAttributes` instead --- .../consul-intention-form/index.hbs} | 38 +++--- .../components/consul-intention-form/index.js | 113 ++++++++++++++++++ .../consul-intention-list/index.hbs | 73 +++++++++++ .../components/consul-intention-list/index.js | 5 + ui-v2/app/controllers/dc/intentions/edit.js | 96 +-------------- ui-v2/app/controllers/dc/intentions/index.js | 5 + ui-v2/app/routes/dc/intentions/create.js | 2 +- .../components/consul-intention-list.scss | 9 ++ .../consul-intention-list/index.scss | 5 + .../consul-intention-list/layout.scss | 0 .../consul-intention-list/skin.scss | 10 ++ ui-v2/app/styles/components/index.scss | 1 + ui-v2/app/styles/components/table.scss | 3 - .../app/styles/routes/dc/intention/index.scss | 13 -- ui-v2/app/templates/dc/intentions/edit.hbs | 9 +- ui-v2/app/templates/dc/intentions/index.hbs | 77 +----------- 16 files changed, 255 insertions(+), 204 deletions(-) rename ui-v2/app/{templates/dc/intentions/-form.hbs => components/consul-intention-form/index.hbs} (77%) create mode 100644 ui-v2/app/components/consul-intention-form/index.js create mode 100644 ui-v2/app/components/consul-intention-list/index.hbs create mode 100644 ui-v2/app/components/consul-intention-list/index.js create mode 100644 ui-v2/app/styles/components/consul-intention-list.scss create mode 100644 ui-v2/app/styles/components/consul-intention-list/index.scss create mode 100644 ui-v2/app/styles/components/consul-intention-list/layout.scss create mode 100644 ui-v2/app/styles/components/consul-intention-list/skin.scss diff --git a/ui-v2/app/templates/dc/intentions/-form.hbs b/ui-v2/app/components/consul-intention-form/index.hbs similarity index 77% rename from ui-v2/app/templates/dc/intentions/-form.hbs rename to ui-v2/app/components/consul-intention-form/index.hbs index 0af22f5798..8ca7013c87 100644 --- a/ui-v2/app/templates/dc/intentions/-form.hbs +++ b/ui-v2/app/components/consul-intention-form/index.hbs @@ -1,12 +1,12 @@ -
+

Source

-
-
+
{{#each (array 'allow' 'deny') as |intent|}} {{/each}}
-
-{{#if create }} - +{{#if _item.isNew }} + {{ else }} - + {{/if}} - -{{# if (and item.ID (not-eq item.ID 'anonymous')) }} + +{{# if (and _item.ID (not-eq _item.ID 'anonymous')) }} - + diff --git a/ui-v2/app/components/consul-intention-form/index.js b/ui-v2/app/components/consul-intention-form/index.js new file mode 100644 index 0000000000..9c608d0e08 --- /dev/null +++ b/ui-v2/app/components/consul-intention-form/index.js @@ -0,0 +1,113 @@ +import Component from '@ember/component'; +import { inject as service } from '@ember/service'; +import { setProperties, set, get } from '@ember/object'; +import { assert } from '@ember/debug'; + +export default Component.extend({ + tagName: '', + dom: service('dom'), + builder: service('form'), + init: function() { + this._super(...arguments); + this.form = this.builder.form('intention'); + }, + didReceiveAttrs: function() { + this._super(...arguments); + if (this.item && this.services && this.nspaces) { + let services = this.services || []; + let nspaces = this.nspaces || []; + let source = services.findBy('Name', this.item.SourceName); + if (!source) { + source = { Name: this.item.SourceName }; + services = [source].concat(services); + } + let destination = services.findBy('Name', this.item.DestinationName); + if (!destination) { + destination = { Name: this.item.DestinationName }; + services = [destination].concat(services); + } + + let sourceNS = nspaces.findBy('Name', this.item.SourceNS); + if (!sourceNS) { + sourceNS = { Name: this.item.SourceNS }; + nspaces = [sourceNS].concat(nspaces); + } + let destinationNS = this.nspaces.findBy('Name', this.item.DestinationNS); + if (!destinationNS) { + destinationNS = { Name: this.item.DestinationNS }; + nspaces = [destinationNS].concat(nspaces); + } + // TODO: Use this.{item,services} when we have this.args + setProperties(this, { + _item: this.form.setData(this.item).getData(), + _services: services, + _nspaces: nspaces, + SourceName: source, + DestinationName: destination, + SourceNS: sourceNS, + DestinationNS: destinationNS, + }); + } else { + assert('@item, @services and @nspaces are required arguments', false); + } + }, + actions: { + createNewLabel: function(template, term) { + return template.replace(/{{term}}/g, term); + }, + isUnique: function(term) { + return !this._services.findBy('Name', term); + }, + submit: function(item, e) { + e.preventDefault(); + this.onsubmit(...arguments); + }, + change: function(e, value, item) { + const event = this.dom.normalizeEvent(e, value); + const form = this.form; + const target = event.target; + + let name, selected, match; + switch (target.name) { + case 'SourceName': + case 'DestinationName': + case 'SourceNS': + case 'DestinationNS': + name = selected = target.value; + // Names can be selected Service EmberObjects or typed in strings + // if its not a string, use the `Name` from the Service EmberObject + if (typeof name !== 'string') { + name = get(target.value, 'Name'); + } + // mutate the value with the string name + // which will be handled by the form + target.value = name; + // these are 'non-form' variables so not on `item` + // these variables also exist in the template so we know + // the current selection + // basically the difference between + // `item.DestinationName` and just `DestinationName` + // see if the name is already in the list + match = this._services.filterBy('Name', name); + if (match.length === 0) { + // if its not make a new 'fake' Service that doesn't exist yet + // and add it to the possible services to make an intention between + selected = { Name: name }; + switch (target.name) { + case 'SourceName': + case 'DestinationName': + set(this, '_services', [selected].concat(this._services.toArray())); + break; + case 'SourceNS': + case 'DestinationNS': + set(this, '_nspaces', [selected].concat(this._nspaces.toArray())); + break; + } + } + set(this, target.name, selected); + break; + } + form.handleEvent(event); + }, + }, +}); diff --git a/ui-v2/app/components/consul-intention-list/index.hbs b/ui-v2/app/components/consul-intention-list/index.hbs new file mode 100644 index 0000000000..aafe0b4863 --- /dev/null +++ b/ui-v2/app/components/consul-intention-list/index.hbs @@ -0,0 +1,73 @@ + + + Source +   + Destination + Precedence + + + + + {{#if (eq item.SourceName '*') }} + All Services (*) + {{else}} + {{item.SourceName}} + {{/if}} + {{! TODO: slugify }} + {{or item.SourceNS 'default'}} + + + + {{item.Action}} + + + + {{#if (eq item.DestinationName '*') }} + All Services (*) + {{else}} + {{item.DestinationName}} + {{/if}} + {{! TODO: slugify }} + {{or item.DestinationNS 'default'}} + + + + {{item.Precedence}} + + + + + + More + + +
  • + Edit +
  • +
  • + +
    +
    +
    +
    + Confirm Delete +
    +

    + Are you sure you want to delete this intention? +

    +
    +
      +
    • + +
    • +
    • + +
    • +
    +
    +
    +
  • +
    +
    +
    +
    diff --git a/ui-v2/app/components/consul-intention-list/index.js b/ui-v2/app/components/consul-intention-list/index.js new file mode 100644 index 0000000000..4798652642 --- /dev/null +++ b/ui-v2/app/components/consul-intention-list/index.js @@ -0,0 +1,5 @@ +import Component from '@ember/component'; + +export default Component.extend({ + tagName: '', +}); diff --git a/ui-v2/app/controllers/dc/intentions/edit.js b/ui-v2/app/controllers/dc/intentions/edit.js index 8e1e72ea8a..8d7b8afb0a 100644 --- a/ui-v2/app/controllers/dc/intentions/edit.js +++ b/ui-v2/app/controllers/dc/intentions/edit.js @@ -1,100 +1,8 @@ import Controller from '@ember/controller'; -import { inject as service } from '@ember/service'; -import { get, set } from '@ember/object'; export default Controller.extend({ - dom: service('dom'), - builder: service('form'), - init: function() { - this._super(...arguments); - this.form = this.builder.form('intention'); - }, - setProperties: function(model) { - let source = model.services.findBy('Name', model.item.SourceName); - - if (!source) { - source = { Name: model.item.SourceName }; - model.services = [source].concat(model.services); - } - let destination = model.services.findBy('Name', model.item.DestinationName); - if (!destination) { - destination = { Name: model.item.DestinationName }; - model.services = [destination].concat(model.services); - } - - let sourceNS = model.nspaces.findBy('Name', model.item.SourceNS); - if (!sourceNS) { - sourceNS = { Name: model.item.SourceNS }; - model.nspaces = [sourceNS].concat(model.nspaces); - } - let destinationNS = model.nspaces.findBy('Name', model.item.DestinationNS); - if (!destinationNS) { - destinationNS = { Name: model.item.DestinationNS }; - model.nspaces = [destinationNS].concat(model.nspaces); - } - this._super({ - ...model, - ...{ - item: this.form.setData(model.item).getData(), - SourceName: source, - DestinationName: destination, - SourceNS: sourceNS, - DestinationNS: destinationNS, - }, - }); - }, actions: { - createNewLabel: function(template, term) { - return template.replace(/{{term}}/g, term); - }, - isUnique: function(term) { - return !this.services.findBy('Name', term); - }, - change: function(e, value, item) { - const event = this.dom.normalizeEvent(e, value); - const form = this.form; - const target = event.target; - - let name, selected, match; - switch (target.name) { - case 'SourceName': - case 'DestinationName': - case 'SourceNS': - case 'DestinationNS': - name = selected = target.value; - // Names can be selected Service EmberObjects or typed in strings - // if its not a string, use the `Name` from the Service EmberObject - if (typeof name !== 'string') { - name = get(target.value, 'Name'); - } - // mutate the value with the string name - // which will be handled by the form - target.value = name; - // these are 'non-form' variables so not on `item` - // these variables also exist in the template so we know - // the current selection - // basically the difference between - // `item.DestinationName` and just `DestinationName` - // see if the name is already in the list - match = this.services.filterBy('Name', name); - if (match.length === 0) { - // if its not make a new 'fake' Service that doesn't exist yet - // and add it to the possible services to make an intention between - selected = { Name: name }; - switch (target.name) { - case 'SourceName': - case 'DestinationName': - set(this, 'services', [selected].concat(this.services.toArray())); - break; - case 'SourceNS': - case 'DestinationNS': - set(this, 'nspaces', [selected].concat(this.nspaces.toArray())); - break; - } - } - set(this, target.name, selected); - break; - } - form.handleEvent(event); + route: function() { + this.send(...arguments); }, }, }); diff --git a/ui-v2/app/controllers/dc/intentions/index.js b/ui-v2/app/controllers/dc/intentions/index.js index 1ee826f789..3dee58bf06 100644 --- a/ui-v2/app/controllers/dc/intentions/index.js +++ b/ui-v2/app/controllers/dc/intentions/index.js @@ -47,4 +47,9 @@ export default Controller.extend(WithSearching, WithFiltering, WithEventSource, filter: function(item, { s = '', currentFilter = '' }) { return currentFilter === '' || get(item, 'Action') === currentFilter; }, + actions: { + route: function() { + this.send(...arguments); + }, + }, }); diff --git a/ui-v2/app/routes/dc/intentions/create.js b/ui-v2/app/routes/dc/intentions/create.js index 0c94f236a2..05edabf226 100644 --- a/ui-v2/app/routes/dc/intentions/create.js +++ b/ui-v2/app/routes/dc/intentions/create.js @@ -42,7 +42,7 @@ export default Route.extend(WithIntentionActions, { }, deactivate: function() { if (get(this.item, 'isNew')) { - this.item.destroyRecord(); + this.item.rollbackAttributes(); } }, }); diff --git a/ui-v2/app/styles/components/consul-intention-list.scss b/ui-v2/app/styles/components/consul-intention-list.scss new file mode 100644 index 0000000000..ee488116c3 --- /dev/null +++ b/ui-v2/app/styles/components/consul-intention-list.scss @@ -0,0 +1,9 @@ +@import './consul-intention-list/index'; +.consul-intention-list { + @extend %consul-intention-list; +} +@media #{$--lt-wide-table} { + %consul-intention-list tr > :nth-last-child(2) { + display: none; + } +} diff --git a/ui-v2/app/styles/components/consul-intention-list/index.scss b/ui-v2/app/styles/components/consul-intention-list/index.scss new file mode 100644 index 0000000000..47a153ed1e --- /dev/null +++ b/ui-v2/app/styles/components/consul-intention-list/index.scss @@ -0,0 +1,5 @@ +@import './skin'; +@import './layout'; +%consul-intention-list td.destination { + @extend %tbody-th; +} diff --git a/ui-v2/app/styles/components/consul-intention-list/layout.scss b/ui-v2/app/styles/components/consul-intention-list/layout.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ui-v2/app/styles/components/consul-intention-list/skin.scss b/ui-v2/app/styles/components/consul-intention-list/skin.scss new file mode 100644 index 0000000000..b69ee10cc1 --- /dev/null +++ b/ui-v2/app/styles/components/consul-intention-list/skin.scss @@ -0,0 +1,10 @@ +%consul-intention-list td strong { + visibility: hidden; +} +%consul-intention-list td.intent-allow strong::before { + @extend %with-arrow-right-color-icon, %as-pseudo; + background-size: 24px; +} +%consul-intention-list td.intent-deny strong::before { + @extend %with-deny-color-icon, %as-pseudo; +} diff --git a/ui-v2/app/styles/components/index.scss b/ui-v2/app/styles/components/index.scss index 982942ba99..0b9add75d7 100644 --- a/ui-v2/app/styles/components/index.scss +++ b/ui-v2/app/styles/components/index.scss @@ -25,6 +25,7 @@ @import './notice'; @import './sort-control'; @import './discovery-chain'; +@import './consul-intention-list'; @import './tabular-details'; @import './tabular-collection'; diff --git a/ui-v2/app/styles/components/table.scss b/ui-v2/app/styles/components/table.scss index c67c7518ec..3f86247daa 100644 --- a/ui-v2/app/styles/components/table.scss +++ b/ui-v2/app/styles/components/table.scss @@ -82,9 +82,6 @@ th span em { tr > .actions { display: none; } - html.template-intention.template-list tr > :nth-last-child(2) { - display: none; - } html.template-service.template-list tr > :last-child { display: none; } diff --git a/ui-v2/app/styles/routes/dc/intention/index.scss b/ui-v2/app/styles/routes/dc/intention/index.scss index ee1b95dfd1..e69de29bb2 100644 --- a/ui-v2/app/styles/routes/dc/intention/index.scss +++ b/ui-v2/app/styles/routes/dc/intention/index.scss @@ -1,13 +0,0 @@ -html.template-intention.template-list td strong { - visibility: hidden; -} -html.template-intention.template-list td.intent-allow strong::before { - @extend %with-arrow-right-color-icon, %as-pseudo; - background-size: 24px; -} -html.template-intention.template-list td.intent-deny strong::before { - @extend %with-deny-color-icon, %as-pseudo; -} -html.template-intention.template-list td.destination { - @extend %tbody-th; -} diff --git a/ui-v2/app/templates/dc/intentions/edit.hbs b/ui-v2/app/templates/dc/intentions/edit.hbs index b560f26921..82c03f09f1 100644 --- a/ui-v2/app/templates/dc/intentions/edit.hbs +++ b/ui-v2/app/templates/dc/intentions/edit.hbs @@ -44,6 +44,13 @@ {{/if}}
    - {{ partial 'dc/intentions/form'}} + \ No newline at end of file diff --git a/ui-v2/app/templates/dc/intentions/index.hbs b/ui-v2/app/templates/dc/intentions/index.hbs index aea5171cbb..3abb77ded1 100644 --- a/ui-v2/app/templates/dc/intentions/index.hbs +++ b/ui-v2/app/templates/dc/intentions/index.hbs @@ -20,79 +20,10 @@ - - - Source -   - Destination - Precedence - - - - - {{#if (eq item.SourceName '*') }} - All Services (*) - {{else}} - {{item.SourceName}} - {{/if}} - {{! TODO: slugify }} - {{or item.SourceNS 'default'}} - - - - {{item.Action}} - - - - {{#if (eq item.DestinationName '*') }} - All Services (*) - {{else}} - {{item.DestinationName}} - {{/if}} - {{! TODO: slugify }} - {{or item.DestinationNS 'default'}} - - - - {{item.Precedence}} - - - - - - More - - -
  • - Edit -
  • -
  • - -
    -
    -
    -
    - Confirm Delete -
    -

    - Are you sure you want to delete this intention? -

    -
    -
      -
    • - -
    • -
    • - -
    • -
    -
    -
    -
  • -
    -
    -
    -
    +