diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml
index d71b1f96e..3debadfdc 100644
--- a/addons/core/translations/resources/en-us.yaml
+++ b/addons/core/translations/resources/en-us.yaml
@@ -279,10 +279,10 @@ storage-bucket:
help: The AWS region to use
access_key_id:
label: Access key ID
- help: The Access key ID generated by AWS for the IAM User to use with this storage bucket. We will not show this data after it is saved, but you can replace.
+ help: The Access key ID generated by AWS for the IAM User to use with this storage bucket. We will not show this data after it is saved, but you can replace it.
secret_access_key:
label: Secret access key
- help: The secret access key to use.
+ help: The secret access key generated by AWS for the IAM user to use with this storage bucket. We will not show this data after it is saved, but you can replace it.
worker_filter:
label: Worker filter
help: Filter for Boundary workers that have network access to your storage. Boolean expression.
diff --git a/addons/rose/addon/styles/hds/themes/dark-mode/index.scss b/addons/rose/addon/styles/hds/themes/dark-mode/index.scss
index 14ab0905d..38ab4cf09 100644
--- a/addons/rose/addon/styles/hds/themes/dark-mode/index.scss
+++ b/addons/rose/addon/styles/hds/themes/dark-mode/index.scss
@@ -102,6 +102,9 @@
--token-color-palette-neutral-200
);
--token-form-indicator-optional-color: var(--token-color-palette-neutral-200);
+ --token-color-foreground-high-contrast: var(
+ --token-color-palette-neutral-700
+ );
}
@media (prefers-color-scheme: dark) {
diff --git a/ui/admin/app/components/form/storage-bucket/index.hbs b/ui/admin/app/components/form/storage-bucket/index.hbs
index 7563e7b61..18018710f 100644
--- a/ui/admin/app/components/form/storage-bucket/index.hbs
+++ b/ui/admin/app/components/form/storage-bucket/index.hbs
@@ -65,7 +65,12 @@
{{#each @scopes as |scope|}}
-
+
{{/each}}
@@ -188,36 +193,7 @@
{{/if}}
- {{else}}
-
- {{t
- 'resources.storage-bucket.form.access_key_id.label'
- }}
- {{t
- 'resources.storage-bucket.form.access_key_id.help'
- }}
- {{#if @model.errors.access_key_id}}
-
- {{#each @model.errors.access_key_id as |error|}}
- {{error.message}}
- {{/each}}
-
- {{/if}}
-
- {{/if}}
- {{#if @model.isNew}}
{{/if}}
+ {{else}}
+
+ {{t
+ 'resources.storage-bucket.form.access_key_id.label'
+ }}
+ {{t
+ 'resources.storage-bucket.form.access_key_id.help'
+ }}
+ {{#if @model.errors.access_key_id}}
+
+ {{#each @model.errors.access_key_id as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{t
+ 'resources.storage-bucket.form.secret_access_key.label'
+ }}
+ {{t
+ 'resources.storage-bucket.form.secret_access_key.help'
+ }}
+ {{#if @model.errors.secret_access_key}}
+
+ {{#each @model.errors.secret_access_key as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
{{/if}}
}
*/
async model() {
diff --git a/ui/admin/tests/acceptance/storage-buckets/create-test-test.js b/ui/admin/tests/acceptance/storage-buckets/create-test.js
similarity index 100%
rename from ui/admin/tests/acceptance/storage-buckets/create-test-test.js
rename to ui/admin/tests/acceptance/storage-buckets/create-test.js
diff --git a/ui/admin/tests/acceptance/storage-buckets/read-test.js b/ui/admin/tests/acceptance/storage-buckets/read-test.js
index f3f47c48c..b0aa243d9 100644
--- a/ui/admin/tests/acceptance/storage-buckets/read-test.js
+++ b/ui/admin/tests/acceptance/storage-buckets/read-test.js
@@ -16,6 +16,9 @@ module('Acceptance | storage-buckets | read', function (hooks) {
let features;
+ const MESSAGE_SELECTOR = '.rose-message-subtitle';
+ const TABLE_LINK_SELECTOR = '.hds-table__tbody tr:first-child a';
+
const instances = {
scopes: {
global: null,
@@ -27,6 +30,8 @@ module('Acceptance | storage-buckets | read', function (hooks) {
const urls = {
globalScope: null,
storageBuckets: null,
+ storageBucket: null,
+ unknownStorageBucket: null,
};
hooks.beforeEach(function () {
@@ -40,19 +45,46 @@ module('Acceptance | storage-buckets | read', function (hooks) {
});
urls.globalScope = `/scopes/global`;
urls.storageBuckets = `${urls.globalScope}/storage-buckets`;
+ urls.storageBucket = `${urls.storageBuckets}/${instances.storageBucket.id}`;
+ urls.unknownStorageBucket = `${urls.storageBuckets}/foo`;
features = this.owner.lookup('service:features');
features.enable('session-recording');
authenticateSession({});
});
- test('visiting storage buckets', async function (assert) {
+ test('visiting a storage bucket', async function (assert) {
assert.expect(1);
await visit(urls.globalScope);
await a11yAudit();
await click(`[href="${urls.storageBuckets}"]`);
+ await a11yAudit();
+ await click(`[href="${urls.storageBucket}"]`);
+ await a11yAudit();
- assert.strictEqual(currentURL(), urls.storageBuckets);
+ assert.strictEqual(currentURL(), urls.storageBucket);
+ });
+
+ test('cannot navigate to a storage bucket without proper authorization', async function (assert) {
+ assert.expect(1);
+ await visit(urls.globalScope);
+ instances.storageBucket.authorized_actions =
+ instances.storageBucket.authorized_actions.filter(
+ (item) => item !== 'read'
+ );
+
+ await click(`[href="${urls.storageBuckets}"]`);
+
+ assert.dom(TABLE_LINK_SELECTOR).doesNotExist();
+ });
+
+ test('visiting an unknown storage bucket displays 404 message', async function (assert) {
+ assert.expect(1);
+
+ await visit(urls.unknownStorageBucket);
+ await a11yAudit();
+
+ assert.dom(MESSAGE_SELECTOR).hasText('Error 404');
});
});
diff --git a/ui/admin/tests/acceptance/storage-buckets/update-test.js b/ui/admin/tests/acceptance/storage-buckets/update-test.js
index 8aa700854..b1f774839 100644
--- a/ui/admin/tests/acceptance/storage-buckets/update-test.js
+++ b/ui/admin/tests/acceptance/storage-buckets/update-test.js
@@ -1,5 +1,5 @@
import { module, test } from 'qunit';
-import { visit, click, fillIn } from '@ember/test-helpers';
+import { visit, click, fillIn, findAll } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
import { Response } from 'miragejs';
@@ -16,6 +16,19 @@ module('Acceptance | storage-buckets | update', function (hooks) {
let features;
+ const BUTTON_SELECTOR = '.rose-form-actions [type="button"]';
+ const SAVE_BUTTON_SELECTOR = '.rose-form-actions [type="submit"]';
+ const NAME_FIELD_SELECTOR = '[name="name"]';
+ const REGION_FIELD_SELECTOR = '[name="region"]';
+ const ALERT_TEXT_SELECTOR = '[role="alert"] div';
+ const FIELD_ERROR_TEXT_SELECTOR = '.hds-form-error__message';
+ const SECRET_FIELD_BUTTON_SELECTOR = '.secret-input [type="button"]';
+ const ACCESS_KEY_ID_FIELD_SELECTOR = '[name="access_key_id"]';
+ const SECRET_ACCESS_KEY_FIELD_SELECTOR = '[name="secret_access_key"]';
+ const NAME_FIELD_TEXT = 'Updated storage-bucket name';
+ const ACCESS_KEY_ID_FIELD_TEXT = 'Updated access key id';
+ const SECRET_ACCESS_KEY_FIELD_TEXT = 'Update secret access key';
+
const instances = {
scopes: {
global: null,
@@ -36,30 +49,97 @@ module('Acceptance | storage-buckets | update', function (hooks) {
});
urls.globalScope = `/scopes/global`;
urls.storageBuckets = `${urls.globalScope}/storage-buckets`;
- (urls.storageBucket = `${urls.storageBuckets}/${instances.storageBucket.id}`),
- (features = this.owner.lookup('service:features'));
+ urls.storageBucket = `${urls.storageBuckets}/${instances.storageBucket.id}`;
+
+ features = this.owner.lookup('service:features');
features.enable('session-recording');
authenticateSession({});
});
test('can save changes to an existing storage-bucket', async function (assert) {
- assert.expect(2);
- await visit(urls.storageBucket);
- await click('.rose-form-actions [type="button"]', 'Click edit mode');
- await fillIn('[name="name"]', 'Updated storage-bucket name');
- await click('.rose-form-actions [type="submit"]');
+ assert.expect(3);
+ await visit(urls.storageBuckets);
+
+ await click(`[href="${urls.storageBucket}"]`);
+ await click(BUTTON_SELECTOR, 'Click edit mode');
+ await fillIn(NAME_FIELD_SELECTOR, NAME_FIELD_TEXT);
+ await click(SAVE_BUTTON_SELECTOR, 'Click save');
+
assert.dom(`[href="${urls.storageBucket}"]`).isVisible();
- assert.dom('input[name="name"]').hasValue('Updated storage-bucket name');
+ assert.dom(NAME_FIELD_SELECTOR).hasValue(NAME_FIELD_TEXT);
+ assert.strictEqual(instances.storageBucket.name, NAME_FIELD_TEXT);
});
test('can cancel changes to an existing storage-bucket', async function (assert) {
- assert.expect(1);
+ assert.expect(2);
const name = instances.storageBucket.name;
- await visit(urls.storageBucket);
- await click('.rose-form-actions [type="button"]', 'Click edit mode');
- await fillIn('[name="name"]', 'Updated storage-bucket name');
- await click('.rose-form-actions [type="button"]');
- await assert.dom('input[name="name"]').hasValue(`${name}`);
+ await visit(urls.storageBuckets);
+
+ await click(`[href="${urls.storageBucket}"]`);
+ await click(BUTTON_SELECTOR, 'Click edit mode');
+ await fillIn(NAME_FIELD_SELECTOR, NAME_FIELD_TEXT);
+ await click(BUTTON_SELECTOR, 'Click cancel');
+
+ assert.dom(NAME_FIELD_SELECTOR).hasValue(`${name}`);
+ assert.strictEqual(instances.storageBucket.name, name);
+ });
+
+ test('can save changes to access key fields', async function (assert) {
+ assert.expect(8);
+ await visit(urls.storageBuckets);
+
+ await click(`[href="${urls.storageBucket}"]`);
+
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).exists({ count: 2 });
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).isDisabled();
+
+ await click(BUTTON_SELECTOR, 'Click edit mode');
+
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).isEnabled();
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).hasText('Edit');
+
+ await click(SECRET_FIELD_BUTTON_SELECTOR);
+ await click(findAll(SECRET_FIELD_BUTTON_SELECTOR)[1]);
+
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).hasText('Cancel');
+
+ await fillIn(ACCESS_KEY_ID_FIELD_SELECTOR, ACCESS_KEY_ID_FIELD_TEXT);
+ await fillIn(
+ SECRET_ACCESS_KEY_FIELD_SELECTOR,
+ SECRET_ACCESS_KEY_FIELD_TEXT
+ );
+ await click(SAVE_BUTTON_SELECTOR, 'Click save');
+
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).isDisabled();
+ assert.dom(ACCESS_KEY_ID_FIELD_SELECTOR).hasValue(ACCESS_KEY_ID_FIELD_TEXT);
+ assert
+ .dom(SECRET_ACCESS_KEY_FIELD_SELECTOR)
+ .hasValue(SECRET_ACCESS_KEY_FIELD_TEXT);
+ });
+
+ test('can cancel changes to access key fields', async function (assert) {
+ assert.expect(3);
+ await visit(urls.storageBuckets);
+
+ await click(`[href="${urls.storageBucket}"]`);
+ await click(BUTTON_SELECTOR, 'Click edit mode');
+ await click(SECRET_FIELD_BUTTON_SELECTOR, 'Click edit button');
+ await click(findAll(SECRET_FIELD_BUTTON_SELECTOR)[1], 'Click edit button');
+ await fillIn(ACCESS_KEY_ID_FIELD_SELECTOR, ACCESS_KEY_ID_FIELD_TEXT);
+ await fillIn(
+ SECRET_ACCESS_KEY_FIELD_SELECTOR,
+ SECRET_ACCESS_KEY_FIELD_TEXT
+ );
+ await click(SECRET_FIELD_BUTTON_SELECTOR, 'Click cancel button');
+ await click(
+ findAll(SECRET_FIELD_BUTTON_SELECTOR)[1],
+ 'Click cancel button'
+ );
+ await click(SAVE_BUTTON_SELECTOR, 'Click save');
+
+ assert.dom(SECRET_FIELD_BUTTON_SELECTOR).isDisabled();
+ assert.dom(ACCESS_KEY_ID_FIELD_SELECTOR).hasNoValue();
+ assert.dom(SECRET_ACCESS_KEY_FIELD_SELECTOR).hasNoValue();
});
test('saving an existing storage-bucket with invalid fields will display error messages', async function (assert) {
@@ -86,11 +166,11 @@ module('Acceptance | storage-buckets | update', function (hooks) {
});
await click(`[href="${urls.storageBucket}"]`);
- await click('.rose-form-actions [type="button"]', 'Activate edit mode');
- await fillIn('[name="region"]', 'random string');
- await click('[type="submit"]');
+ await click(BUTTON_SELECTOR, 'Activate edit mode');
+ await fillIn(REGION_FIELD_SELECTOR, 'random string');
+ await click(SAVE_BUTTON_SELECTOR);
- assert.dom('[role="alert"] div').hasText('The request was invalid.');
- assert.dom('.hds-form-error__message').hasText('Region is required.');
+ assert.dom(ALERT_TEXT_SELECTOR).hasText('The request was invalid.');
+ assert.dom(FIELD_ERROR_TEXT_SELECTOR).hasText('Region is required.');
});
});