diff --git a/ui/core/app/components/form/auth-method/index.hbs b/ui/core/app/components/form/auth-method/index.hbs
new file mode 100644
index 000000000..7c1bc5162
--- /dev/null
+++ b/ui/core/app/components/form/auth-method/index.hbs
@@ -0,0 +1,53 @@
+
+
+
+
+ {{#if @model.errors.name}}
+
+ {{#each @model.errors.name as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+ {{#if @model.errors.description}}
+
+ {{#each @model.errors.description as |error|}}
+ {{error.message}}
+ {{/each}}
+
+ {{/if}}
+
+
+
+
\ No newline at end of file
diff --git a/ui/core/app/controllers/scopes/scope/auth-methods.js b/ui/core/app/controllers/scopes/scope/auth-methods.js
new file mode 100644
index 000000000..ab152cf62
--- /dev/null
+++ b/ui/core/app/controllers/scopes/scope/auth-methods.js
@@ -0,0 +1,18 @@
+import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
+
+export default class ScopesScopeAuthMethodsController extends Controller {
+ // =services
+
+ @service intl;
+
+ // =attributes
+
+ /**
+ * Translated auth-methods breadcrumb
+ * @type {string}
+ */
+ get breadCrumb() {
+ return this.intl.t('resources.auth-methods');
+ }
+}
diff --git a/ui/core/app/controllers/scopes/scope/auth-methods/auth-method.js b/ui/core/app/controllers/scopes/scope/auth-methods/auth-method.js
new file mode 100644
index 000000000..1005f0216
--- /dev/null
+++ b/ui/core/app/controllers/scopes/scope/auth-methods/auth-method.js
@@ -0,0 +1,13 @@
+import Controller from '@ember/controller';
+
+export default class ScopesScopeAuthMethodsAuthMethodController extends Controller {
+ // =attributes
+
+ /**
+ * An auth-method breadcrumb
+ * @type {string}
+ */
+ get breadCrumb() {
+ return this.model.displayName;
+ }
+}
diff --git a/ui/core/app/controllers/scopes/scope/auth-methods/new.js b/ui/core/app/controllers/scopes/scope/auth-methods/new.js
new file mode 100644
index 000000000..ba550f456
--- /dev/null
+++ b/ui/core/app/controllers/scopes/scope/auth-methods/new.js
@@ -0,0 +1,18 @@
+import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
+
+export default class ScopesScopeAuthMethodsNewController extends Controller {
+ // =services
+
+ @service intl;
+
+ // =attributes
+
+ /**
+ * Translated new auth-method breadcrumb
+ * @type {string}
+ */
+ get breadCrumb() {
+ return this.intl.t('titles.new');
+ }
+}
diff --git a/ui/core/app/router.js b/ui/core/app/router.js
index cf5cea5d6..af71f6132 100644
--- a/ui/core/app/router.js
+++ b/ui/core/app/router.js
@@ -36,7 +36,10 @@ Router.map(function () {
});
this.route('new');
});
- this.route('auth-methods', function() {});
+ this.route('auth-methods', function() {
+ this.route('auth-method', { path: ':auth_method_id' }, function() {});
+ this.route('new');
+ });
});
});
});
diff --git a/ui/core/app/routes/scopes/scope/auth-methods.js b/ui/core/app/routes/scopes/scope/auth-methods.js
index 112c40248..ffad801fa 100644
--- a/ui/core/app/routes/scopes/scope/auth-methods.js
+++ b/ui/core/app/routes/scopes/scope/auth-methods.js
@@ -1,6 +1,13 @@
import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
export default class ScopesScopeAuthMethodsRoute extends Route {
+ // =services
+
+ @service intl;
+ @service notify;
+
// =methods
/**
@@ -11,4 +18,36 @@ export default class ScopesScopeAuthMethodsRoute extends Route {
const { id: scopeID} = this.modelFor('scopes.scope');
return this.store.findAll('auth-method', { adapterOptions: { scopeID } });
}
+
+ // =actions
+ /**
+ * Rollback changes to an auth-method.
+ * @param {AuthMethodModel} authMethod
+ */
+ @action
+ cancel(authMethod) {
+ const { isNew } = authMethod;
+ authMethod.rollbackAttributes();
+ if (isNew) this.transitionTo('scopes.scope.auth-methods');
+ }
+
+ /**
+ * Save an auth-method in current scope.
+ * @param {AuthMethodModel} authMethod
+ */
+ @action
+ async save(authMethod) {
+ const { isNew } = authMethod;
+ try {
+ await authMethod.save();
+ this.refresh();
+ this.notify.success(
+ this.intl.t(isNew ? 'notify.create-success' : 'notify.save-success')
+ );
+ this.transitionTo('scopes.scope.auth-methods.auth-method', authMethod);
+ } catch (error) {
+ //TODO: replace with translated strings
+ this.notify.error(error.message, { closeAfter: null });
+ }
+ }
}
diff --git a/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js b/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js
new file mode 100644
index 000000000..5cc752eac
--- /dev/null
+++ b/ui/core/app/routes/scopes/scope/auth-methods/auth-method.js
@@ -0,0 +1,16 @@
+import Route from '@ember/routing/route';
+
+export default class ScopesScopeAuthMethodsAuthMethodRoute extends Route {
+ // =methods
+
+ /**
+ * Load a single auth-method in current scope.
+ * @param {object} params
+ * @param {string} params.auth_method_id
+ * @return {authMethodModel}
+ */
+ async model({ auth_method_id}) {
+ const { id: scopeID } = this.modelFor('scopes.scope');
+ return this.store.findRecord('auth-method', auth_method_id, { adapterOptions: { scopeID }});
+ }
+}
diff --git a/ui/core/app/routes/scopes/scope/auth-methods/auth-method/index.js b/ui/core/app/routes/scopes/scope/auth-methods/auth-method/index.js
new file mode 100644
index 000000000..5cef508e0
--- /dev/null
+++ b/ui/core/app/routes/scopes/scope/auth-methods/auth-method/index.js
@@ -0,0 +1,4 @@
+import Route from '@ember/routing/route';
+
+export default class ScopesScopeAuthMethodsAuthMethodIndexRoute extends Route {
+}
diff --git a/ui/core/app/routes/scopes/scope/auth-methods/new.js b/ui/core/app/routes/scopes/scope/auth-methods/new.js
new file mode 100644
index 000000000..ceeb6a5d7
--- /dev/null
+++ b/ui/core/app/routes/scopes/scope/auth-methods/new.js
@@ -0,0 +1,14 @@
+import Route from '@ember/routing/route';
+
+export default class ScopesScopeAuthMethodsNewRoute extends Route {
+ // =methods
+
+ /**
+ * Create a new unsaved auth-method.
+ * @return {AuthMethodModel}
+ */
+ model() {
+ const scopeModel = this.modelFor('scopes.scope');
+ return this.store.createRecord('auth-method', { type: 'password', scopeModel });
+ }
+}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method.hbs
new file mode 100644
index 000000000..c24cd6895
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method.hbs
@@ -0,0 +1 @@
+{{outlet}}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/index.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/index.hbs
new file mode 100644
index 000000000..c08c3fd4a
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/index.hbs
@@ -0,0 +1,28 @@
+
+
+ {{t "resources.auth-method"}}
+
+ {{t (concat 'auth.method-types.' @model.type)}}
+
+
+
+
+
+
+
+
+
+
+ {{t 'titles.details'}}
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/index.hbs b/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
index 2d5456c58..a5bc4f485 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
@@ -3,6 +3,18 @@
{{t "resources.auth-methods"}}
+
+
+
+
+
+ {{#if @model}}
+
+ {{t "titles.new"}}
+
+ {{/if}}
+
+
{{#if @model}}
@@ -19,12 +31,17 @@
{{#each @model as |authMethod|}}
- {{authMethod.name}}
- {{authMethod.description}}
+
+ {{authMethod.name}}
+
+ {{authMethod.description}}
- {{authMethod.type}}
+ {{t (concat 'auth.method-types.' authMethod.type)}}
{{authMethod.id}}
@@ -40,6 +57,10 @@
{{t 'descriptions.auth-methods-welcome'}}
+
+
+ {{t 'titles.new'}}
+
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/new.hbs b/ui/core/app/templates/scopes/scope/auth-methods/new.hbs
new file mode 100644
index 000000000..44c4f35d6
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/auth-methods/new.hbs
@@ -0,0 +1,19 @@
+{{title (t "titles.new")}}
+
+
+
+ {{t "titles.new"}}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ui/core/tests/acceptance/auth-methods-test.js b/ui/core/tests/acceptance/auth-methods-test.js
new file mode 100644
index 000000000..5b816f253
--- /dev/null
+++ b/ui/core/tests/acceptance/auth-methods-test.js
@@ -0,0 +1,94 @@
+import { module, test } from 'qunit';
+import { visit, currentURL } from '@ember/test-helpers';
+import { setupApplicationTest } from 'ember-qunit';
+import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
+import a11yAudit from 'ember-a11y-testing/test-support/audit';
+import {
+ authenticateSession,
+ // These are left here intentionally for future reference.
+ //currentSession,
+ //invalidateSession,
+} from 'ember-simple-auth/test-support';
+
+module('Acceptance | auth methods', function (hooks) {
+ setupApplicationTest(hooks);
+ setupMirage(hooks);
+
+ const instances = {
+ scopes: {
+ global: null,
+ org: null
+ },
+ authMethod: null
+ };
+ const urls = {
+ orgScope: null,
+ authMethods: null
+ };
+
+ hooks.beforeEach(function () {
+ // Setup Mirage mock resources for this test
+ instances.scopes.global = this.server.create('scope', { id: 'global' });
+ instances.scopes.org = this.server.create('scope', { type: 'org',
+ scope: { id: instances.scopes.global.id, type: instances.scopes.global.type }
+ });
+ instances.authMethod = this.server.create('auth-method', {
+ scope: {
+ id: instances.scopes.org.id,
+ type: instances.scopes.org.type
+ }
+ });
+
+ // Generate route URLs for resources
+ urls.orgScope = `/scopes/${instances.scopes.org.id}`;
+ urls.authMethods = `${urls.orgScope}/auth-methods`;
+ });
+
+ test('visiting auth methods', async function (assert) {
+ assert.expect(1);
+ authenticateSession();
+ await visit(urls.authMethods);
+ await a11yAudit();
+ assert.equal(currentURL(), urls.authMethods);
+ });
+
+ test('can navigate to an auth method form', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('can update an auth method and save changes', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('can update an auth method and cancel changes', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('can create new auth method', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('can cancel new auth method creation', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('saving a new auth method with invalid fields displays error messages', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('errors are displayed when save on auth method fails', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('errors are displayed when delete on an auth method fails', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('saving a new auth method with invalid fields displays error messages', async function (assert) {
+ assert.expect(0);
+ });
+
+ test('saving an existing auth method with invalid fields displays error messages', async function (assert) {
+ assert.expect(0);
+ });
+});
diff --git a/ui/core/tests/integration/components/form/auth-method-test.js b/ui/core/tests/integration/components/form/auth-method-test.js
new file mode 100644
index 000000000..267e516b5
--- /dev/null
+++ b/ui/core/tests/integration/components/form/auth-method-test.js
@@ -0,0 +1,23 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | form/auth-method', function (hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ this.submit = () => {};
+ this.cancel = () => {};
+ this.model = { type: 'password' };
+
+ await render(hbs`
+ `);
+
+ assert.ok(find('form'));
+ });
+});
diff --git a/ui/core/tests/unit/controllers/scopes/scope/auth-methods-test.js b/ui/core/tests/unit/controllers/scopes/scope/auth-methods-test.js
new file mode 100644
index 000000000..20cbdbe00
--- /dev/null
+++ b/ui/core/tests/unit/controllers/scopes/scope/auth-methods-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | scopes/scope/auth-methods', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:scopes/scope/auth-methods');
+ assert.ok(controller);
+ });
+});
diff --git a/ui/core/tests/unit/controllers/scopes/scope/auth-methods/auth-method-test.js b/ui/core/tests/unit/controllers/scopes/scope/auth-methods/auth-method-test.js
new file mode 100644
index 000000000..ad19d3e67
--- /dev/null
+++ b/ui/core/tests/unit/controllers/scopes/scope/auth-methods/auth-method-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | scopes/scope/auth-methods/auth-method', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:scopes/scope/auth-methods/auth-method');
+ assert.ok(controller);
+ });
+});
diff --git a/ui/core/tests/unit/controllers/scopes/scope/auth-methods/new-test.js b/ui/core/tests/unit/controllers/scopes/scope/auth-methods/new-test.js
new file mode 100644
index 000000000..2d5306d6a
--- /dev/null
+++ b/ui/core/tests/unit/controllers/scopes/scope/auth-methods/new-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | scopes/scope/auth-methods/new', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:scopes/scope/auth-methods/new');
+ assert.ok(controller);
+ });
+});
diff --git a/ui/core/tests/unit/routes/scopes/scope/auth-methods/auth-method-test.js b/ui/core/tests/unit/routes/scopes/scope/auth-methods/auth-method-test.js
new file mode 100644
index 000000000..36b2e2f2d
--- /dev/null
+++ b/ui/core/tests/unit/routes/scopes/scope/auth-methods/auth-method-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | scopes/scope/auth-methods/auth-method', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:scopes/scope/auth-methods/auth-method');
+ assert.ok(route);
+ });
+});
diff --git a/ui/core/tests/unit/routes/scopes/scope/auth-methods/auth-method/index-test.js b/ui/core/tests/unit/routes/scopes/scope/auth-methods/auth-method/index-test.js
new file mode 100644
index 000000000..5a51858df
--- /dev/null
+++ b/ui/core/tests/unit/routes/scopes/scope/auth-methods/auth-method/index-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | scopes/scope/auth-methods/auth-method/index', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:scopes/scope/auth-methods/auth-method/index');
+ assert.ok(route);
+ });
+});
diff --git a/ui/core/tests/unit/routes/scopes/scope/auth-methods/new-test.js b/ui/core/tests/unit/routes/scopes/scope/auth-methods/new-test.js
new file mode 100644
index 000000000..6eea2751c
--- /dev/null
+++ b/ui/core/tests/unit/routes/scopes/scope/auth-methods/new-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | scopes/scope/auth-methods/new', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:scopes/scope/auth-methods/new');
+ assert.ok(route);
+ });
+});
diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml
index 2fe1ad5f8..10e48f67c 100644
--- a/ui/core/translations/en-us.yaml
+++ b/ui/core/translations/en-us.yaml
@@ -31,6 +31,7 @@ resources:
project: Project
host-catalog: Host Catalog
host-catalogs: Host Catalogs
+ auth-method: Auth Method
auth-methods: Auth Methods
titles:
iam: IAM