diff --git a/.changelog/9513.txt b/.changelog/9513.txt
new file mode 100644
index 000000000..70bde0bff
--- /dev/null
+++ b/.changelog/9513.txt
@@ -0,0 +1,3 @@
+```release-note:bug
+ui: Fixes an issue where intention description or metadata could be overwritten if saved from the topology view.
+```
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/index.hbs b/ui/packages/consul-ui/app/components/topology-metrics/index.hbs
index 9828e12fa..ba4ee349c 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/index.hbs
+++ b/ui/packages/consul-ui/app/components/topology-metrics/index.hbs
@@ -3,7 +3,7 @@
{{#if (gt @topology.Downstreams.length 0)}}
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/notifications/index.hbs b/ui/packages/consul-ui/app/components/topology-metrics/notifications/index.hbs
new file mode 100644
index 000000000..7ef4000c5
--- /dev/null
+++ b/ui/packages/consul-ui/app/components/topology-metrics/notifications/index.hbs
@@ -0,0 +1,19 @@
+{{#if (eq @type 'create')}}
+ {{#if (eq @status 'success') }}
+ Your intention has been added.
+ {{else}}
+ There was an error adding your intention.
+ {{/if}}
+{{else if (eq @type 'update') }}
+ {{#if (eq @status 'success') }}
+ Your intention has been saved.
+ {{else}}
+ There was an error saving your intention.
+ {{/if}}
+{{/if}}
+{{#let @error.errors.firstObject as |error|}}
+ {{#if error.detail }}
+ {{concat '(' (if error.status (concat error.status ': ')) error.detail ')'}}
+ {{/if}}
+{{/let}}
+
diff --git a/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs b/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs
index ad03bf940..b8241d37a 100644
--- a/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs
+++ b/ui/packages/consul-ui/app/components/topology-metrics/popover/index.hbs
@@ -16,16 +16,25 @@
<:body>
- Add an intention that allows these two services to connect.
+ {{#if @item.Intention.HasExact}}
+ Change the action of this intention to allow.
+ {{else}}
+ Add an intention that allows these two services to connect.
+ {{/if}}
diff --git a/ui/packages/consul-ui/tests/acceptance/dc/services/show/topology.feature b/ui/packages/consul-ui/tests/acceptance/dc/services/show/topology.feature
new file mode 100644
index 000000000..29bec89f2
--- /dev/null
+++ b/ui/packages/consul-ui/tests/acceptance/dc/services/show/topology.feature
@@ -0,0 +1,43 @@
+@setupApplicationTest
+Feature: dc / services / show / topology: Intention Create
+ Background:
+ Given 1 datacenter model with the value "datacenter"
+ And 1 intention model from yaml
+ ---
+ SourceNS: default
+ SourceName: web
+ DestinationNS: default
+ DestinationName: db
+ ID: intention-id
+ ---
+ And 1 node model
+ And 1 service model from yaml
+ ---
+ - Service:
+ Name: web
+ Kind: ~
+ ---
+ And 1 topology model from yaml
+ ---
+ Downstreams: []
+ Upstreams:
+ - Name: db
+ Namespace: default
+ Datacenter: datacenter
+ Intention: {}
+ ---
+ When I visit the service page for yaml
+ ---
+ dc: datacenter
+ service: web
+ ---
+ Scenario: Allow a connection between service and upstream by saving an intention
+ When I click ".consul-topology-metrics [data-test-action]"
+ And I click ".consul-topology-metrics [data-test-confirm]"
+ And "[data-notification]" has the "success" class
+ Scenario: There was an error saving the intention
+ Given the url "/v1/connect/intentions/exact?source=default%2Fweb&destination=default%2Fdb&dc=datacenter" responds with a 500 status
+ When I click ".consul-topology-metrics [data-test-action]"
+ And I click ".consul-topology-metrics [data-test-confirm]"
+ And "[data-notification]" has the "error" class
+
diff --git a/ui/packages/consul-ui/tests/acceptance/steps/dc/services/show/topology-steps.js b/ui/packages/consul-ui/tests/acceptance/steps/dc/services/show/topology-steps.js
new file mode 100644
index 000000000..3231912b9
--- /dev/null
+++ b/ui/packages/consul-ui/tests/acceptance/steps/dc/services/show/topology-steps.js
@@ -0,0 +1,10 @@
+import steps from '../../../steps';
+
+// step definitions that are shared between features should be moved to the
+// tests/acceptance/steps/steps.js file
+
+export default function(assert) {
+ return steps(assert).then('I should find a file', function() {
+ assert.ok(true, this.step);
+ });
+}
diff --git a/ui/packages/consul-ui/tests/helpers/type-to-url.js b/ui/packages/consul-ui/tests/helpers/type-to-url.js
index 68138bbf8..905480bee 100644
--- a/ui/packages/consul-ui/tests/helpers/type-to-url.js
+++ b/ui/packages/consul-ui/tests/helpers/type-to-url.js
@@ -38,6 +38,9 @@ export default function(type) {
case 'nspace':
requests = ['/v1/namespaces', '/v1/namespace/'];
break;
+ case 'topology':
+ requests = ['/v1/internal/ui/service-topology'];
+ break;
}
// TODO: An instance of URL should come in here (instead of 2 args)
return function(url, method) {