diff --git a/ui/app/components/secure-variable-form.hbs b/ui/app/components/secure-variable-form.hbs
index f5275dca7..780e3726d 100644
--- a/ui/app/components/secure-variable-form.hbs
+++ b/ui/app/components/secure-variable-form.hbs
@@ -12,11 +12,19 @@
@type="text"
@value={{@model.path}}
placeholder="/path/to/variable"
- class="input path-input"
+ class="input path-input {{if this.duplicatePathWarning "error"}}"
disabled={{not @model.isNew}}
+ {{on "input" this.validatePath}}
{{autofocus}}
/>
+ {{#if this.duplicatePathWarning}}
+
+ There is already a Secure Variable located at {{@model.path}}.
+
+ Please choose a different path, or edit the existing Secure Variable.
+
+ {{/if}}
{{#each @model.keyValues as |entry iter|}}
diff --git a/ui/app/components/secure-variable-form.js b/ui/app/components/secure-variable-form.js
index c2ef9f398..77404e148 100644
--- a/ui/app/components/secure-variable-form.js
+++ b/ui/app/components/secure-variable-form.js
@@ -1,13 +1,28 @@
+// @ts-check
+
import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { inject as service } from '@ember/service';
+import { trimPath } from '../helpers/trim-path';
+
export default class SecureVariableFormComponent extends Component {
@service router;
+ @service store;
@tracked
shouldHideValues = true;
+ /**
+ * @typedef {Object} DuplicatePathWarning
+ * @property {string} path
+ */
+
+ /**
+ * @type {DuplicatePathWarning}
+ */
+ @tracked duplicatePathWarning = null;
+
get valueFieldType() {
return this.shouldHideValues ? 'password' : 'text';
}
@@ -16,6 +31,22 @@ export default class SecureVariableFormComponent extends Component {
return !this.args.model?.path;
}
+ @action
+ validatePath(e) {
+ const value = trimPath([e.target.value]);
+ let existingVariable = this.store
+ .peekAll('variable')
+ .without(this.args.model)
+ .find((v) => v.path === value);
+ if (existingVariable) {
+ this.duplicatePathWarning = {
+ path: existingVariable.path,
+ };
+ } else {
+ this.duplicatePathWarning = null;
+ }
+ }
+
@action
toggleShowHide() {
this.shouldHideValues = !this.shouldHideValues;
diff --git a/ui/app/routes/variables/variable/edit.js b/ui/app/routes/variables/variable/edit.js
index cd8cdf9ca..1e4d10ab3 100644
--- a/ui/app/routes/variables/variable/edit.js
+++ b/ui/app/routes/variables/variable/edit.js
@@ -1,3 +1,7 @@
import Route from '@ember/routing/route';
-export default class VariablesVariableEditRoute extends Route {}
+export default class VariablesVariableEditRoute extends Route {
+ model() {
+ return this.modelFor('variables.variable');
+ }
+}
diff --git a/ui/app/styles/components/secure-variables.scss b/ui/app/styles/components/secure-variables.scss
index fcba9448d..6c51a0a8c 100644
--- a/ui/app/styles/components/secure-variables.scss
+++ b/ui/app/styles/components/secure-variables.scss
@@ -7,6 +7,15 @@
&:disabled {
background-color: #f5f5f5;
}
+ &.error {
+ color: $red;
+ border-color: $red;
+ }
+ }
+
+ .duplicate-path-error {
+ position: relative;
+ animation: slide-in 0.3s ease-out;
}
.key-value {
@@ -45,3 +54,15 @@ table.path-tree {
}
}
}
+
+@keyframes slide-in {
+ 0% {
+ top: 10px;
+ opacity: 0;
+ }
+
+ 100% {
+ top: 0px;
+ opacity: 1;
+ }
+}
diff --git a/ui/app/templates/variables/variable/edit.hbs b/ui/app/templates/variables/variable/edit.hbs
index e6c58b8a8..8ebf6e268 100644
--- a/ui/app/templates/variables/variable/edit.hbs
+++ b/ui/app/templates/variables/variable/edit.hbs
@@ -1,5 +1,2 @@
{{page-title "Edit Secure Variable"}}
-
-
+