From c81e3357d7d082260a145ef4f3c9e1c1022c5b9a Mon Sep 17 00:00:00 2001
From: lisbet-alvarez <107949262+lisbet-alvarez@users.noreply.github.com>
Date: Fri, 17 Mar 2023 08:31:51 -0700
Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20create=20form=20componen?=
=?UTF-8?q?t=20for=20storage=20bucket=20(#118)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* feat: 🎸 create form component for storage bucket
✅ Closes: ICU-8235
---
addons/core/translations/resources/en-us.yaml | 26 +-
.../components/form/storage-bucket/index.hbs | 249 ++++++++++++++++++
.../components/form/storage-bucket/index.js | 20 ++
.../scopes/scope/storage-buckets/new.js | 21 ++
.../routes/scopes/scope/storage-buckets.js | 38 ++-
.../scopes/scope/storage-buckets/new.js | 35 ++-
.../scopes/scope/storage-buckets/index.hbs | 4 +-
.../scopes/scope/storage-buckets/new.hbs | 26 +-
.../scopes/scope/storage-buckets/new-test.js | 16 ++
9 files changed, 427 insertions(+), 8 deletions(-)
create mode 100644 ui/admin/app/components/form/storage-bucket/index.hbs
create mode 100644 ui/admin/app/components/form/storage-bucket/index.js
create mode 100644 ui/admin/app/controllers/scopes/scope/storage-buckets/new.js
create mode 100644 ui/admin/tests/unit/controllers/scopes/scope/storage-buckets/new-test.js
diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml
index 3e6ee2b6b..9f2fb54f8 100644
--- a/addons/core/translations/resources/en-us.yaml
+++ b/addons/core/translations/resources/en-us.yaml
@@ -238,8 +238,30 @@ storage-bucket:
actions:
delete: Delete Storage Bucket
form:
- scope: Scope
- provider: Provider
+ scope:
+ label: Scope
+ help: You will be able to associate this storage bucket with any target.
+ provider:
+ label: Provider
+ help: Boundary currently only supports Amazon S3 storage.
+ bucket_name:
+ label: Bucket name
+ help: The name of this bucket in AWS
+ bucket_prefix:
+ label: Bucket prefix
+ help: The base path where session recordings will be stored.
+ region:
+ label: Region
+ help: The AWS region to use
+ access_key_id:
+ label: Access key ID
+ help: The AWS access key ID to use.
+ secret_access_key:
+ label: Secret access key
+ help: The secret access key to use.
+ worker_filter:
+ label: Worker filter
+ help: Filter for Boundary workers that have network access to your storage. Boolean expression.
project:
title: Project
title_plural: Projects
diff --git a/ui/admin/app/components/form/storage-bucket/index.hbs b/ui/admin/app/components/form/storage-bucket/index.hbs
new file mode 100644
index 000000000..2413fd29f
--- /dev/null
+++ b/ui/admin/app/components/form/storage-bucket/index.hbs
@@ -0,0 +1,249 @@
+{{!
+ Copyright (c) HashiCorp, Inc.
+ SPDX-License-Identifier: MPL-2.0
+}}
+
+
+
+ {{t 'form.name.label'}}
+ {{t 'form.name.help'}}
+ {{#if @model.errors.name}}
+
+ {{#each @model.errors.name as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{t 'form.description.label'}}
+ {{t 'form.description.help'}}
+ {{#if @model.errors.description}}
+
+ {{#each @model.errors.description as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+ {{#if (or @model.isNew form.isEditable)}}
+
+ {{t 'resources.storage-bucket.form.scope.label'}}
+ {{t
+ 'resources.storage-bucket.form.scope.help'
+ }}
+
+ {{#each @scopes as |scope|}}
+
+ {{/each}}
+
+
+ {{else if @model.scope}}
+
+ {{t 'resources.storage-bucket.form.scope.label'}}
+ {{t
+ 'resources.storage-bucket.form.scope.help'
+ }}
+
+ {{/if}}
+
+
+ {{t 'titles.provider'}}
+ {{t
+ 'resources.storage-bucket.form.provider.help'
+ }}
+
+
+
+ {{t 'resources.storage-bucket.form.bucket_name.label'}}
+ {{t
+ 'resources.storage-bucket.form.bucket_name.help'
+ }}
+ {{#if @model.errors.bucket_name}}
+
+ {{#each @model.errors.bucket_name as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{t 'resources.storage-bucket.form.bucket_prefix.label'}}
+ {{t
+ 'resources.storage-bucket.form.bucket_prefix.help'
+ }}
+ {{#if @model.errors.bucket_prefix}}
+
+ {{#each @model.errors.bucket_prefix as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{t 'resources.storage-bucket.form.region.label'}}
+ {{t
+ 'resources.storage-bucket.form.region.help'
+ }}
+ {{#if @model.errors.region}}
+
+ {{#each @model.errors.region as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{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}}
+
+
+
+ {{t 'resources.storage-bucket.form.worker_filter.label'}}
+
+ {{t 'resources.storage-bucket.form.worker_filter.help'}}
+ {{! TODO: Link to the correct url for worker-filters }}
+ {{t
+ 'actions.learn-more'
+ }}
+
+ {{#if @model.errors.worker_filter}}
+
+ {{#each @model.errors.worker_filter as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+ {{#if (can 'save model' @model)}}
+
+ {{/if}}
+
\ No newline at end of file
diff --git a/ui/admin/app/components/form/storage-bucket/index.js b/ui/admin/app/components/form/storage-bucket/index.js
new file mode 100644
index 000000000..108ee5fb9
--- /dev/null
+++ b/ui/admin/app/components/form/storage-bucket/index.js
@@ -0,0 +1,20 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import Component from '@glimmer/component';
+import { action } from '@ember/object';
+
+export default class FormStorageBucketComponent extends Component {
+ // =actions
+
+ @action
+ updateScope(event) {
+ const selectedScopeId = event.target.value;
+ const selectedScopeModel = this.args.scopes.find(
+ (element) => element.model.id === selectedScopeId
+ ).model;
+ this.args.model.scopeModel = selectedScopeModel;
+ }
+}
diff --git a/ui/admin/app/controllers/scopes/scope/storage-buckets/new.js b/ui/admin/app/controllers/scopes/scope/storage-buckets/new.js
new file mode 100644
index 000000000..40f8fcfdc
--- /dev/null
+++ b/ui/admin/app/controllers/scopes/scope/storage-buckets/new.js
@@ -0,0 +1,21 @@
+/**
+ * Copyright (c) HashiCorp, Inc.
+ * SPDX-License-Identifier: MPL-2.0
+ */
+
+import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
+
+export default class ScopesScopeStorageBucketsNewController extends Controller {
+ // =services
+
+ @service intl;
+
+ /**
+ * Breadcrumb for new route
+ * @type {string}
+ */
+ get breadCrumb() {
+ return this.intl.t('resources.storage-bucket.titles.new');
+ }
+}
diff --git a/ui/admin/app/routes/scopes/scope/storage-buckets.js b/ui/admin/app/routes/scopes/scope/storage-buckets.js
index 56b2632b6..ca713dd12 100644
--- a/ui/admin/app/routes/scopes/scope/storage-buckets.js
+++ b/ui/admin/app/routes/scopes/scope/storage-buckets.js
@@ -5,12 +5,14 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { loading } from 'ember-loading';
+import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeStorageBucketsRoute extends Route {
// =services
@service store;
- @service intl;
@service session;
@service can;
@service router;
@@ -31,10 +33,42 @@ export default class ScopesScopeStorageBucketsRoute extends Route {
async model() {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
- if (this.can.can('list storage-bucket', scope, { collection: 'storage-buckets' })) {
+ if (
+ this.can.can('list storage-bucket', scope, {
+ collection: 'storage-buckets',
+ })
+ ) {
return this.store.query('storage-bucket', { scope_id });
}
}
// =actions
+
+ /**
+ * Handle save
+ * @param {StorageBucketModel} storageBucket
+ */
+ @action
+ @loading
+ @notifyError(({ message }) => message)
+ @notifySuccess('notifications.save-success')
+ async save(storageBucket) {
+ await storageBucket.save();
+ await this.router.transitionTo(
+ 'scopes.scope.storage-buckets.storage-bucket',
+ storageBucket
+ );
+ this.refresh();
+ }
+
+ /**
+ * Rollback changes on storage buckets.
+ * @param {StorageBucketModel} storageBucket
+ */
+ @action
+ cancel(storageBucket) {
+ const { isNew } = storageBucket;
+ storageBucket.rollbackAttributes();
+ if (isNew) this.router.transitionTo('scopes.scope.storage-buckets');
+ }
}
diff --git a/ui/admin/app/routes/scopes/scope/storage-buckets/new.js b/ui/admin/app/routes/scopes/scope/storage-buckets/new.js
index d318e1a66..130dfe198 100644
--- a/ui/admin/app/routes/scopes/scope/storage-buckets/new.js
+++ b/ui/admin/app/routes/scopes/scope/storage-buckets/new.js
@@ -5,6 +5,10 @@
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
+import {
+ TYPE_STORAGE_BUCKET_PLUGIN,
+ TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
+} from 'api/models/storage-bucket';
export default class ScopesScopeStorageBucketsNewRoute extends Route {
// =services
@@ -19,8 +23,37 @@ export default class ScopesScopeStorageBucketsNewRoute extends Route {
*/
model() {
const scopeModel = this.modelFor('scopes.scope');
- const record = this.store.createRecord('storage-bucket');
+ const record = this.store.createRecord('storage-bucket', {
+ type: TYPE_STORAGE_BUCKET_PLUGIN,
+ compositeType: TYPE_STORAGE_BUCKET_PLUGIN_AWS_S3,
+ });
record.scopeModel = scopeModel;
return record;
}
+
+ async afterModel() {
+ let scopes;
+ const currentScope = this.modelFor('scopes.scope');
+ const orgScopes = (
+ await this.store.query('scope', { scope_id: 'global' })
+ ).map((scope) => ({ model: scope }));
+ if (currentScope.id === 'global') {
+ scopes = [{ model: currentScope }, ...orgScopes];
+ } else {
+ scopes = [
+ { model: this.store.peekRecord('scope', 'global') },
+ ...orgScopes,
+ ];
+ }
+ this.scopes = scopes;
+ }
+
+ /**
+ * Adds available global and org scopes to the context.
+ * @param {Controller} controller
+ */
+ setupController(controller) {
+ super.setupController(...arguments);
+ controller.set('scopes', this.scopes);
+ }
}
diff --git a/ui/admin/app/templates/scopes/scope/storage-buckets/index.hbs b/ui/admin/app/templates/scopes/scope/storage-buckets/index.hbs
index 01c093f4c..fab3a2a7f 100644
--- a/ui/admin/app/templates/scopes/scope/storage-buckets/index.hbs
+++ b/ui/admin/app/templates/scopes/scope/storage-buckets/index.hbs
@@ -37,8 +37,8 @@
@columns={{array
(hash label=(t 'form.name.label'))
(hash label=(t 'form.id.label'))
- (hash label=(t 'resources.storage-bucket.form.provider'))
- (hash label=(t 'resources.storage-bucket.form.scope'))
+ (hash label=(t 'resources.storage-bucket.form.provider.label'))
+ (hash label=(t 'resources.storage-bucket.form.scope.label'))
(hash label='')
}}
>
diff --git a/ui/admin/app/templates/scopes/scope/storage-buckets/new.hbs b/ui/admin/app/templates/scopes/scope/storage-buckets/new.hbs
index 233691fac..e1b859492 100644
--- a/ui/admin/app/templates/scopes/scope/storage-buckets/new.hbs
+++ b/ui/admin/app/templates/scopes/scope/storage-buckets/new.hbs
@@ -3,4 +3,28 @@
SPDX-License-Identifier: MPL-2.0
}}
-{{page-title (t 'titles.new')}}
\ No newline at end of file
+{{page-title (t 'titles.new')}}
+
+
+
+
+
+
+
+ {{! TODO: Add valid doc link and description}}
+
+ {{t 'resources.storage-bucket.titles.new'}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/admin/tests/unit/controllers/scopes/scope/storage-buckets/new-test.js b/ui/admin/tests/unit/controllers/scopes/scope/storage-buckets/new-test.js
new file mode 100644
index 000000000..3f12de7c5
--- /dev/null
+++ b/ui/admin/tests/unit/controllers/scopes/scope/storage-buckets/new-test.js
@@ -0,0 +1,16 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'admin/tests/helpers';
+
+module(
+ 'Unit | Controller | scopes/scope/storage-buckets/new',
+ function (hooks) {
+ setupTest(hooks);
+
+ test('it exists', function (assert) {
+ let controller = this.owner.lookup(
+ 'controller:scopes/scope/storage-buckets/new'
+ );
+ assert.ok(controller);
+ });
+ }
+);