diff --git a/ui/core/app/router.js b/ui/core/app/router.js
index effcb4523..6800b5103 100644
--- a/ui/core/app/router.js
+++ b/ui/core/app/router.js
@@ -54,7 +54,9 @@ Router.map(function () {
});
this.route('groups', function () {
- this.route('group', { path: ':group_id' }, function () {});
+ this.route('group', { path: ':group_id' }, function () {
+ this.route('members');
+ });
this.route('new');
});
diff --git a/ui/core/app/routes/scopes/scope/groups/group/members.js b/ui/core/app/routes/scopes/scope/groups/group/members.js
new file mode 100644
index 000000000..7e2dc6658
--- /dev/null
+++ b/ui/core/app/routes/scopes/scope/groups/group/members.js
@@ -0,0 +1,50 @@
+import Route from '@ember/routing/route';
+import { action } from '@ember/object';
+import { inject as service } from '@ember/service';
+
+export default class ScopesScopeGroupsGroupMembersRoute extends Route {
+
+ // =services
+
+ @service intl;
+ @service notify;
+
+ // =methods
+
+ /**
+ * Empty out all users before loading members.
+ */
+ beforeModel() {
+ this.store.unloadAll('user');
+ }
+
+ /**
+ * Returns users associated with this group.
+ * @return {Promise{[UserModel]}}
+ */
+ async model() {
+ const { id: scopeID } = this.modelFor('scopes.scope');
+ const group = this.modelFor('scopes.scope.groups.group');
+ await this.store.findAll('user', { adapterOptions: { scopeID } });
+ return group;
+ }
+
+ // =actions
+
+ /**
+ * Remove a member from the current role and redirect to members index.
+ * @param {GroupModel} group
+ * @param {UserModel} member
+ */
+ @action
+ async removeMember(group, member) {
+ try {
+ await group.removeMember(member.id);
+ this.notify.success(this.intl.t('notify.delete-success'));
+ } catch (error) {
+ // TODO: replace with translated strings
+ this.notify.error(error.message, { closeAfter: null });
+ }
+ }
+
+}
diff --git a/ui/core/app/templates/scopes/scope/groups/group.hbs b/ui/core/app/templates/scopes/scope/groups/group.hbs
index d66e83390..bb0ba8b8a 100644
--- a/ui/core/app/templates/scopes/scope/groups/group.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/group.hbs
@@ -1,3 +1,40 @@
{{title @model.displayName}}
-{{outlet}}
+
+
+
+
+
+
+
+ {{t "resources.group"}}
+
+
+
+
+
+ {{t 'titles.details'}}
+
+
+ {{t 'titles.members'}}
+
+
+
+
+
+
+
+ {{t 'actions.delete-group'}}
+
+
+
+
+
+ {{outlet}}
+
+
+
diff --git a/ui/core/app/templates/scopes/scope/groups/group/index.hbs b/ui/core/app/templates/scopes/scope/groups/group/index.hbs
index ffc59c7cd..1fb27689d 100644
--- a/ui/core/app/templates/scopes/scope/groups/group/index.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/group/index.hbs
@@ -1,39 +1,5 @@
-
-
-
-
-
-
-
- {{t "resources.group"}}
-
-
-
-
-
- {{t 'titles.details'}}
-
-
-
-
-
-
-
- {{t 'actions.delete-group'}}
-
-
-
-
-
-
-
-
-
+
diff --git a/ui/core/app/templates/scopes/scope/groups/group/members.hbs b/ui/core/app/templates/scopes/scope/groups/group/members.hbs
new file mode 100644
index 000000000..a2445b90d
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/groups/group/members.hbs
@@ -0,0 +1,53 @@
+{{title (t 'titles.members')}}
+
+{{#if @model.members}}
+
+
+
+
+ {{t 'form.label.name'}}
+ {{t 'form.label.id'}}
+ {{t "form.label.actions"}}
+
+
+
+ {{#each @model.members as |member|}}
+
+
+ {{member.displayName}}
+
+
+ {{member.id}}
+
+
+
+
+ {{t "actions.remove"}}
+
+
+
+
+ {{/each}}
+
+
+
+{{else}}
+
+
+
+
+ {{t "descriptions.group-members-welcome"}}
+
+
+
+
+{{/if}}
diff --git a/ui/core/tests/acceptance/groups-test.js b/ui/core/tests/acceptance/groups-test.js
index 0d622f1f0..c33014378 100644
--- a/ui/core/tests/acceptance/groups-test.js
+++ b/ui/core/tests/acceptance/groups-test.js
@@ -217,4 +217,9 @@ module('Acceptance | groups', function (hooks) {
'Displays primary error message.'
);
});
+
+ test('can view group members', async function (assert) {
+ assert.expect(0);
+ });
+
});
diff --git a/ui/core/tests/unit/routes/scopes/scope/groups/group/members-test.js b/ui/core/tests/unit/routes/scopes/scope/groups/group/members-test.js
new file mode 100644
index 000000000..5872d940c
--- /dev/null
+++ b/ui/core/tests/unit/routes/scopes/scope/groups/group/members-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | scopes/scope/groups/group/members', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:scopes/scope/groups/group/members');
+ assert.ok(route);
+ });
+});
diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml
index 655821ec8..d33ec0514 100644
--- a/ui/core/translations/en-us.yaml
+++ b/ui/core/translations/en-us.yaml
@@ -93,6 +93,8 @@ titles:
no-host-set-hosts: No Hosts Available
no-host-sets-for-target: No Host Sets Available
role-principals-welcome: No Principals Associated
+ members: Members
+ group-members-welcome: Welcome to Members
descriptions:
host-catalogs: Overview of collections of hosts and host sets.
empty-set: There are no items to display yet. You may be able to add items or try back later.
@@ -109,6 +111,7 @@ descriptions:
no-host-set-hosts: Before associating hosts with this host set, create hosts within the host catalog.
no-host-sets-for-target: No host sets are available to add to this target.
role-principals-welcome: No principals are available in this role.
+ group-members-welcome: Users belonging to this group appear here.
states:
info: Info
success: Success