From 715805f0de46c957c14c8cd18bf80da4b2e7ff13 Mon Sep 17 00:00:00 2001
From: Randall Morey
Date: Wed, 30 Sep 2020 10:08:24 -0400
Subject: [PATCH 01/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20API=20suppor?=
=?UTF-8?q?t=20for=20user=20accounts?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
addons/api/addon/models/user.js | 81 ++++++++++++-
addons/api/addon/serializers/user.js | 33 ++++++
addons/api/app/serializers/user.js | 1 +
addons/api/tests/unit/models/user-test.js | 111 +++++++++++++++++-
.../unit/serializers/application-test.js | 6 +-
.../api/tests/unit/serializers/user-test.js | 77 ++++++++++++
6 files changed, 303 insertions(+), 6 deletions(-)
create mode 100644 addons/api/addon/serializers/user.js
create mode 100644 addons/api/app/serializers/user.js
create mode 100644 addons/api/tests/unit/serializers/user-test.js
diff --git a/addons/api/addon/models/user.js b/addons/api/addon/models/user.js
index 51053788f..c2be5cfb0 100644
--- a/addons/api/addon/models/user.js
+++ b/addons/api/addon/models/user.js
@@ -1,3 +1,82 @@
import GeneratedUserModel from '../generated/models/user';
+import { attr } from '@ember-data/model';
+import { A } from '@ember/array';
-export default class UserModel extends GeneratedUserModel {}
+export default class UserModel extends GeneratedUserModel {
+
+ // =attributes
+
+ /**
+ * Accounts is read-only under normal circumstances. But accounts can
+ * be persisted via calls to `addAccounts()` or `removeAccounts()`.
+ */
+ @attr({
+ readOnly: true,
+ defaultValue: () => A(),
+ emptyArrayIfMissing: true,
+ })
+ account_ids;
+
+ // =methods
+
+ /**
+ * Adds accounts via the `add-accounts` method.
+ * See serializer and adapter for more information.
+ * @param {[string]} accountIDs
+ * @param {object} options
+ * @param {object} options.adapterOptions
+ * @return {Promise}
+ */
+ addAccounts(accountIDs, options = { adapterOptions: {} }) {
+ const defaultAdapterOptions = {
+ method: 'add-accounts',
+ accountIDs,
+ };
+ // There is no "deep merge" in ES.
+ // All of this nonsense is here to ensure we get
+ // a decent merge of `adapterOptions`.
+ return this.save({
+ ...options,
+ adapterOptions: {
+ ...defaultAdapterOptions,
+ ...options.adapterOptions,
+ },
+ });
+ }
+
+ /**
+ * Remove accounts via the `remove-accounts` method.
+ * See serializer and adapter for more information.
+ * @param {[string]} accountIDs
+ * @param {object} options
+ * @param {object} options.adapterOptions
+ * @return {Promise}
+ */
+ removeAccounts(accountIDs, options = { adapterOptions: {} }) {
+ const defaultAdapterOptions = {
+ method: 'remove-accounts',
+ accountIDs,
+ };
+ // There is no "deep merge" in ES.
+ // All of this nonsense is here to ensure we get
+ // a decent merge of `adapterOptions`.
+ return this.save({
+ ...options,
+ adapterOptions: {
+ ...defaultAdapterOptions,
+ ...options.adapterOptions,
+ },
+ });
+ }
+
+ /**
+ * Remove a single account via the `remove-accounts` method.
+ * @param {number} accountID
+ * @param {object} options
+ * @return {Promise}
+ */
+ removeAccount(accountID, options) {
+ return this.removeAccounts([accountID], options);
+ }
+
+}
diff --git a/addons/api/addon/serializers/user.js b/addons/api/addon/serializers/user.js
new file mode 100644
index 000000000..9c4a47194
--- /dev/null
+++ b/addons/api/addon/serializers/user.js
@@ -0,0 +1,33 @@
+import ApplicationSerializer from './application';
+
+export default class UserSerializer extends ApplicationSerializer {
+ // =methods
+
+ /**
+ * If `adapterOptions.accountIDs` is set (to an array of user IDs),
+ * then the payload is serialized via `serializewithAccounts`.
+ * @override
+ * @param {Snapshot} snapshot
+ * @return {object}
+ */
+ serialize(snapshot) {
+ let serialized = super.serialize(...arguments);
+ const accountIDs = snapshot?.adapterOptions?.accountIDs;
+ if (accountIDs) serialized =
+ this.serializewithAccounts(snapshot, accountIDs);
+ return serialized;
+ }
+
+ /**
+ * Returns a payload containing only the `account_ids` array (and version).
+ * @param {Snapshot} snapshot
+ * @param {[string]} account_ids
+ * @return {object}
+ */
+ serializewithAccounts(snapshot, account_ids) {
+ return {
+ version: snapshot.attr('version'),
+ account_ids,
+ };
+ }
+}
diff --git a/addons/api/app/serializers/user.js b/addons/api/app/serializers/user.js
new file mode 100644
index 000000000..5c5a92643
--- /dev/null
+++ b/addons/api/app/serializers/user.js
@@ -0,0 +1 @@
+export { default } from 'api/serializers/user';
diff --git a/addons/api/tests/unit/models/user-test.js b/addons/api/tests/unit/models/user-test.js
index df69a6501..75a8f0916 100644
--- a/addons/api/tests/unit/models/user-test.js
+++ b/addons/api/tests/unit/models/user-test.js
@@ -1,12 +1,115 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
+import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
module('Unit | Model | user', function (hooks) {
setupTest(hooks);
+ setupMirage(hooks);
- test('it exists', function (assert) {
- let store = this.owner.lookup('service:store');
- let model = store.createRecord('user', {});
- assert.ok(model);
+ test('it has an `addAccounts` method that users a specific POST API endpoint and serialization', async function (assert) {
+ assert.expect(1);
+ this.server.post('/v1/users/123abc:add-accounts', (schema, request) => {
+ const body = JSON.parse(request.requestBody);
+ assert.deepEqual(body, {
+ account_ids: ['123_abc', 'foobar'],
+ version: 1,
+ });
+ });
+ const store = this.owner.lookup('service:store');
+ store.push({
+ data: {
+ id: '123abc',
+ type: 'user',
+ attributes: {
+ name: 'User',
+ description: 'Description',
+ account_ids: ['1', '2'],
+ version: 1,
+ scope: {
+ scope_id: 'o_1',
+ type: 'scope',
+ },
+ },
+ },
+ });
+ const model = store.peekRecord('user', '123abc');
+ await model.addAccounts(['123_abc', 'foobar']);
+ });
+
+ test('it has a `removeAccounts` method that users a specific POST API endpoint and serialization', async function (assert) {
+ assert.expect(1);
+ this.server.post('/v1/users/123abc:remove-accounts', (schema, request) => {
+ const body = JSON.parse(request.requestBody);
+ assert.deepEqual(body, {
+ account_ids: ['1', '3'],
+ version: 1,
+ });
+ });
+ const store = this.owner.lookup('service:store');
+ store.push({
+ data: {
+ id: '123abc',
+ type: 'user',
+ attributes: {
+ name: 'user',
+ description: 'Description',
+ account_ids: ['4', '5'],
+ version: 1,
+ scope: {
+ scope_id: 'o_1',
+ type: 'scope',
+ },
+ },
+ },
+ });
+ const model = store.peekRecord('user', '123abc');
+ await model.removeAccounts(['1', '3']);
+ });
+
+ test('it has a `removeAccount` method that deletes a single account set using `removeAccounts` method', async function (assert) {
+ assert.expect(1);
+ this.server.post('/v1/users/123abc:remove-accounts', (schema, request) => {
+ const body = JSON.parse(request.requestBody);
+ assert.deepEqual(body, {
+ account_ids: ['3'],
+ version: 1,
+ });
+ });
+ const store = this.owner.lookup('service:store');
+ store.push({
+ data: {
+ id: '123abc',
+ type: 'user',
+ attributes: {
+ name: 'user',
+ description: 'Description',
+ account_ids: ['1', '3'],
+ version: 1,
+ scope: {
+ scope_id: 'o_1',
+ type: 'scope',
+ },
+ },
+ },
+ });
+ const model = store.peekRecord('user', '123abc');
+ await model.removeAccount('3');
+ });
+
+ test('it defaults `accounts_ids` to an empty array when model instance does not define it', function (assert) {
+ assert.expect(1);
+ const store = this.owner.lookup('service:store');
+ store.push({
+ data: {
+ id: 'user_123',
+ type: 'user',
+ },
+ });
+ const user = store.peekRecord('user', 'user_123');
+ assert.equal(
+ user.account_ids.length,
+ 0,
+ 'User has empty account_ids by default'
+ );
});
});
diff --git a/addons/api/tests/unit/serializers/application-test.js b/addons/api/tests/unit/serializers/application-test.js
index 5c2c07a20..10de9d4fb 100644
--- a/addons/api/tests/unit/serializers/application-test.js
+++ b/addons/api/tests/unit/serializers/application-test.js
@@ -154,7 +154,11 @@ module('Unit | Serializer | application', function (hooks) {
data: {
id: '1',
type: 'user',
- attributes: { name: 'User 1', scope: { scope_id: 'o_123' } },
+ attributes: {
+ name: 'User 1',
+ account_ids: [],
+ scope: { scope_id: 'o_123' }
+ },
relationships: {},
},
});
diff --git a/addons/api/tests/unit/serializers/user-test.js b/addons/api/tests/unit/serializers/user-test.js
new file mode 100644
index 000000000..c0d2bd061
--- /dev/null
+++ b/addons/api/tests/unit/serializers/user-test.js
@@ -0,0 +1,77 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Serializer | user', function (hooks) {
+ setupTest(hooks);
+
+ test('it serializes users normally, without accounts', function (assert) {
+ assert.expect(1);
+ const store = this.owner.lookup('service:store');
+ const serializer = store.serializerFor('user');
+ const record = store.createRecord('user', {
+ name: 'user',
+ description: 'Description',
+ account_ids: ['1', '2'],
+ version: 1,
+ });
+ const snapshot = record._createSnapshot();
+ snapshot.adapterOptions = {};
+ const serializedRecord = serializer.serialize(snapshot);
+ assert.deepEqual(serializedRecord, {
+ name: 'user',
+ description: 'Description',
+ version: 1,
+ });
+ });
+
+ test('it serializes only host sets and version when an `adapterOptions.accountIDs` array is passed', function (assert) {
+ assert.expect(1);
+ const store = this.owner.lookup('service:store');
+ const serializer = store.serializerFor('user');
+ const record = store.createRecord('user', {
+ name: 'user',
+ description: 'Description',
+ account_ids: ['1', '2'],
+ version: 1,
+ });
+ const snapshot = record._createSnapshot();
+ snapshot.adapterOptions = {
+ accountIDs: ['4', '5'],
+ };
+ const serializedRecord = serializer.serialize(snapshot);
+ assert.deepEqual(serializedRecord, {
+ account_ids: ['4', '5'],
+ version: 1,
+ });
+ });
+
+ test('it normalizes missing account_ids to empty array', function (assert) {
+ assert.expect(1);
+ const store = this.owner.lookup('service:store');
+ const serializer = store.serializerFor('user');
+ const user = store.createRecord('user').constructor;
+ const payload = {
+ id: '1',
+ name: 'user 1',
+ scope: { id: 'o_123' },
+ };
+ const normalized = serializer.normalizeSingleResponse(
+ store,
+ user,
+ payload
+ );
+ assert.deepEqual(normalized, {
+ included: [],
+ data: {
+ id: '1',
+ type: 'user',
+ attributes: {
+ name: 'user 1',
+ scope: { scope_id: 'o_123' },
+ account_ids: [],
+ },
+ relationships: {},
+ },
+ });
+ });
+});
From 956981b06e7ec41b3bc5179f78aa4979b4c15b63 Mon Sep 17 00:00:00 2001
From: Randall Morey
Date: Wed, 30 Sep 2020 10:45:39 -0400
Subject: [PATCH 02/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20user=20accou?=
=?UTF-8?q?nts=20listing=20and=20remove?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../form/account/password/index.hbs | 2 -
ui/core/app/router.js | 4 +-
ui/core/app/routes/scopes/scope/users/user.js | 23 +++
.../scopes/scope/users/user/accounts.js | 51 +++++++
.../auth-method/accounts/index.hbs | 2 +-
.../app/templates/scopes/scope/users/user.hbs | 24 ++-
.../scopes/scope/users/user/-actions.hbs | 9 ++
.../scopes/scope/users/user/-header.hbs | 3 +
.../scopes/scope/users/user/-navigation.hbs | 8 +
.../scopes/scope/users/user/accounts.hbs | 53 +++++++
.../scopes/scope/users/user/index.hbs | 46 +-----
ui/core/mirage/config.js | 25 +++
ui/core/mirage/factories/auth-method.js | 9 +-
ui/core/mirage/models/user.js | 5 +-
ui/core/mirage/scenarios/default.js | 2 +-
ui/core/mirage/serializers/user.js | 15 +-
.../tests/acceptance/users/accounts-test.js | 142 ++++++++++++++++++
.../scopes/scope/users/user/accounts-test.js | 11 ++
ui/core/translations/form/en-us.yaml | 6 +-
ui/core/translations/resources/en-us.yaml | 10 +-
20 files changed, 393 insertions(+), 57 deletions(-)
create mode 100644 ui/core/app/routes/scopes/scope/users/user/accounts.js
create mode 100644 ui/core/app/templates/scopes/scope/users/user/-actions.hbs
create mode 100644 ui/core/app/templates/scopes/scope/users/user/-header.hbs
create mode 100644 ui/core/app/templates/scopes/scope/users/user/-navigation.hbs
create mode 100644 ui/core/app/templates/scopes/scope/users/user/accounts.hbs
create mode 100644 ui/core/tests/acceptance/users/accounts-test.js
create mode 100644 ui/core/tests/unit/routes/scopes/scope/users/user/accounts-test.js
diff --git a/ui/core/app/components/form/account/password/index.hbs b/ui/core/app/components/form/account/password/index.hbs
index e2890657e..34b7ed0e4 100644
--- a/ui/core/app/components/form/account/password/index.hbs
+++ b/ui/core/app/components/form/account/password/index.hbs
@@ -55,7 +55,6 @@
@value={{@model.attributes.login_name}}
@label={{t "form.login_name.label"}}
@error={{@model.errors.login_name}}
- @helperText={{t "form.login_name.help"}}
readonly={{false}}
as |field|>
{{#if @model.errors.login_name}}
@@ -74,7 +73,6 @@
@value={{this.password}}
@label={{t "form.password.label"}}
@error={{@model.errors.password}}
- @helperText={{t "form.password.help"}}
readonly={{false}}
autocomplete="new-password"
as |field|>
diff --git a/ui/core/app/router.js b/ui/core/app/router.js
index 0894289f9..8142aa85a 100644
--- a/ui/core/app/router.js
+++ b/ui/core/app/router.js
@@ -58,7 +58,9 @@ Router.map(function () {
});
this.route('users', function () {
- this.route('user', { path: ':user_id' }, function () {});
+ this.route('user', { path: ':user_id' }, function () {
+ this.route('accounts');
+ });
this.route('new');
});
diff --git a/ui/core/app/routes/scopes/scope/users/user.js b/ui/core/app/routes/scopes/scope/users/user.js
index d26912707..2d7ed072e 100644
--- a/ui/core/app/routes/scopes/scope/users/user.js
+++ b/ui/core/app/routes/scopes/scope/users/user.js
@@ -12,4 +12,27 @@ export default class ScopesScopeUsersUserRoute extends Route {
async model({ user_id }) {
return this.store.findRecord('user', user_id);
}
+
+ /**
+ * Renders the route-set specific page sections
+ * @override
+ */
+ renderTemplate() {
+ super.renderTemplate(...arguments);
+
+ this.render('scopes/scope/users/user/-header', {
+ into: 'scopes/scope/users/user',
+ outlet: 'header',
+ });
+
+ this.render('scopes/scope/users/user/-actions', {
+ into: 'scopes/scope/users/user',
+ outlet: 'actions',
+ });
+
+ this.render('scopes/scope/users/user/-navigation', {
+ into: 'scopes/scope/users/user',
+ outlet: 'navigation',
+ });
+ }
}
diff --git a/ui/core/app/routes/scopes/scope/users/user/accounts.js b/ui/core/app/routes/scopes/scope/users/user/accounts.js
new file mode 100644
index 000000000..cb00ca24e
--- /dev/null
+++ b/ui/core/app/routes/scopes/scope/users/user/accounts.js
@@ -0,0 +1,51 @@
+import Route from '@ember/routing/route';
+import { action } from '@ember/object';
+import { inject as service } from '@ember/service';
+import { hash, all } from 'rsvp';
+import loading from 'ember-loading/decorator';
+
+export default class ScopesScopeUsersUserAccountsRoute extends Route {
+ // =services
+
+ @service intl;
+ @service notify;
+
+ // =methods
+
+ /**
+ * Returns users associated with this user.
+ * @return {Promise{user: UserModel, accounts: Promise{[AccountModel]}}}
+ */
+ model() {
+ const { id: scopeID } = this.modelFor('scopes.scope');
+ const user = this.modelFor('scopes.scope.users.user');
+ return hash({
+ user,
+ accounts: all(
+ user.account_ids.map((id) =>
+ this.store.findRecord('account', id, { adapterOptions: { scopeID } })
+ )
+ ),
+ });
+ }
+
+ // =actions
+
+ /**
+ * Remove a account from the current role and redirect to accounts index.
+ * @param {UserModel} user
+ * @param {AccountModel} account
+ */
+ @action
+ @loading
+ async removeAccount(user, account) {
+ try {
+ await user.removeAccount(account.id);
+ await this.refresh();
+ this.notify.success(this.intl.t('notifications.remove-success'));
+ } catch (error) {
+ // TODO: replace with translated strings
+ this.notify.error(error.message, { closeAfter: null });
+ }
+ }
+}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
index 81b93da9c..7df042046 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
@@ -4,7 +4,7 @@
{{t 'form.name.label'}}
- {{t 'form.login_name.label'}}
+ {{t 'form.username.label'}}
{{t 'form.id.label'}}
diff --git a/ui/core/app/templates/scopes/scope/users/user.hbs b/ui/core/app/templates/scopes/scope/users/user.hbs
index d66e83390..2a878ff51 100644
--- a/ui/core/app/templates/scopes/scope/users/user.hbs
+++ b/ui/core/app/templates/scopes/scope/users/user.hbs
@@ -1,3 +1,25 @@
{{title @model.displayName}}
-{{outlet}}
+
+
+
+
+
+
+
+ {{outlet "header"}}
+
+
+
+ {{outlet "navigation"}}
+
+
+
+ {{outlet "actions"}}
+
+
+
+ {{outlet}}
+
+
+
diff --git a/ui/core/app/templates/scopes/scope/users/user/-actions.hbs b/ui/core/app/templates/scopes/scope/users/user/-actions.hbs
new file mode 100644
index 000000000..b72d4c322
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/users/user/-actions.hbs
@@ -0,0 +1,9 @@
+
+
+ {{t 'actions.delete-user'}}
+
+
diff --git a/ui/core/app/templates/scopes/scope/users/user/-header.hbs b/ui/core/app/templates/scopes/scope/users/user/-header.hbs
new file mode 100644
index 000000000..2b107e842
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/users/user/-header.hbs
@@ -0,0 +1,3 @@
+{{t "resources.user.title"}}
+{{t "resources.user.description"}}
+{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/users/user/-navigation.hbs b/ui/core/app/templates/scopes/scope/users/user/-navigation.hbs
new file mode 100644
index 000000000..0228c92e8
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/users/user/-navigation.hbs
@@ -0,0 +1,8 @@
+
+
+ {{t 'titles.details'}}
+
+
+ {{t 'resources.user.messages.accounts.title'}}
+
+
diff --git a/ui/core/app/templates/scopes/scope/users/user/accounts.hbs b/ui/core/app/templates/scopes/scope/users/user/accounts.hbs
new file mode 100644
index 000000000..66c808da9
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/users/user/accounts.hbs
@@ -0,0 +1,53 @@
+{{title (t 'resources.user.messages.accounts.title')}}
+
+{{#if @model.accounts}}
+
+
+
+
+ {{t 'form.username.label'}}
+ {{t 'form.id.label'}}
+ {{t "titles.actions"}}
+
+
+
+ {{#each @model.accounts as |account|}}
+
+
+ {{account.username}}
+
+
+ {{account.id}}
+
+
+
+
+ {{t "actions.remove"}}
+
+
+
+
+ {{/each}}
+
+
+
+{{else}}
+
+
+
+
+ {{t "resources.user.messages.accounts.description"}}
+
+
+
+
+{{/if}}
diff --git a/ui/core/app/templates/scopes/scope/users/user/index.hbs b/ui/core/app/templates/scopes/scope/users/user/index.hbs
index 35db006e9..67714eca0 100644
--- a/ui/core/app/templates/scopes/scope/users/user/index.hbs
+++ b/ui/core/app/templates/scopes/scope/users/user/index.hbs
@@ -1,41 +1,5 @@
-
-
-
-
-
-
-
- {{t "resources.user.title"}}
- {{t "resources.user.description"}}
- {{@model.id}}
-
-
-
-
-
- {{t 'actions.delete-user'}}
-
-
-
-
-
-
-
- {{t 'titles.details'}}
-
-
-
-
-
-
-
-
-
+
diff --git a/ui/core/mirage/config.js b/ui/core/mirage/config.js
index 3d332f121..678d5fafb 100644
--- a/ui/core/mirage/config.js
+++ b/ui/core/mirage/config.js
@@ -90,6 +90,31 @@ export default function() {
this.get('/users/:id');
this.patch('/users/:id');
this.del('/users/:id');
+ this.post('/users/:idMethod', function ({ users }, { params: { idMethod } }) {
+ const attrs = this.normalizedRequestAttrs();
+ const id = idMethod.split(':')[0];
+ const method = idMethod.split(':')[1];
+ const user = users.find(id);
+ const updatedAttrs = {
+ version: attrs.version,
+ accountIds: user.accountIds
+ };
+ // If adding accounts, push them into the array
+ if (method === 'add-accounts') {
+ attrs.accountIds.forEach(id => {
+ if (!updatedAttrs.accountIds.includes(id)) {
+ updatedAttrs.accountIds.push(id);
+ }
+ });
+ }
+ // If deleting accounts, filter them out of the array
+ if (method === 'remove-accounts') {
+ updatedAttrs.accountIds = updatedAttrs.accountIds.filter(id => {
+ return !attrs.accountIds.includes(id);
+ });
+ }
+ return user.update(updatedAttrs);
+ });
// IAM: Groups
this.get('/groups', ({ groups }, { queryParams: { scope_id: scopeId } }) => {
diff --git a/ui/core/mirage/factories/auth-method.js b/ui/core/mirage/factories/auth-method.js
index 80254614a..61d29726b 100644
--- a/ui/core/mirage/factories/auth-method.js
+++ b/ui/core/mirage/factories/auth-method.js
@@ -5,12 +5,15 @@ export default factory.extend({
id: (i) => `auth-method-id-${i}`,
/**
- * Adds accounts to auth method.
+ * Adds accounts (with associated users) to auth method.
*/
- withAccounts: trait({
+ withAccountsAndUsers: trait({
afterCreate(authMethod, server) {
const { scope } = authMethod;
- server.createList('account', 5, { scope, authMethod });
+ server.createList('user', 5, { scope }).map(user => {
+ const { id } = server.create('account', { scope, authMethod });
+ user.update({ accountIds: [id] });
+ });
}
})
diff --git a/ui/core/mirage/models/user.js b/ui/core/mirage/models/user.js
index 08b1f5ad3..45cf14952 100644
--- a/ui/core/mirage/models/user.js
+++ b/ui/core/mirage/models/user.js
@@ -1,7 +1,8 @@
-import { Model, belongsTo } from 'ember-cli-mirage';
+import { Model, belongsTo, hasMany } from 'ember-cli-mirage';
export default Model.extend({
- scope: belongsTo()
+ scope: belongsTo(),
+ accounts: hasMany('account')
});
diff --git a/ui/core/mirage/scenarios/default.js b/ui/core/mirage/scenarios/default.js
index 5d1a85fe6..e4cd01854 100644
--- a/ui/core/mirage/scenarios/default.js
+++ b/ui/core/mirage/scenarios/default.js
@@ -15,7 +15,7 @@ export default function(server) {
// Auth
server.createList('auth-method', 3, { scope: globalScope });
- server.createList('auth-method', 3, { scope: orgScope }, 'withAccounts');
+ server.createList('auth-method', 3, { scope: orgScope }, 'withAccountsAndUsers');
// Groups and Users
server.createList('group', 5, { scope: orgScope }, 'withMembers');
diff --git a/ui/core/mirage/serializers/user.js b/ui/core/mirage/serializers/user.js
index 142cbf508..0ef9298f5 100644
--- a/ui/core/mirage/serializers/user.js
+++ b/ui/core/mirage/serializers/user.js
@@ -1,5 +1,18 @@
import ApplicationSerializer from './application';
+import { underscore } from '@ember/string';
export default ApplicationSerializer.extend({
- modelName: 'user'
+ modelName: 'user',
+
+ keyForRelationshipIds(relationshipName) {
+ return `${this._container.inflector.singularize(
+ underscore(relationshipName)
+ )}_ids`;
+ },
+
+ _hashForModel(model) {
+ const json = ApplicationSerializer.prototype._hashForModel.apply(this, arguments);
+ if (model.accountIds.length) json.account_ids = model.accountIds;
+ return json;
+ }
});
diff --git a/ui/core/tests/acceptance/users/accounts-test.js b/ui/core/tests/acceptance/users/accounts-test.js
new file mode 100644
index 000000000..0dead76e1
--- /dev/null
+++ b/ui/core/tests/acceptance/users/accounts-test.js
@@ -0,0 +1,142 @@
+import { module, test } from 'qunit';
+import { visit, currentURL, click, find, findAll } 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 { Response } from 'miragejs';
+import {
+ authenticateSession,
+ // These are left here intentionally for future reference.
+ //currentSession,
+ //invalidateSession,
+} from 'ember-simple-auth/test-support';
+
+module('Acceptance | users | accounts', function (hooks) {
+ setupApplicationTest(hooks);
+ setupMirage(hooks);
+
+ const instances = {
+ scopes: {
+ global: null,
+ org: null,
+ },
+ user: null,
+ };
+ const urls = {
+ orgScope: null,
+ users: null,
+ user: null,
+ accounts: null,
+ addAccounts: null,
+ };
+ let accountsCount;
+
+ hooks.beforeEach(function () {
+ authenticateSession({});
+ instances.scopes.global = this.server.create('scope', { id: 'global' });
+ instances.scopes.org = this.server.create('scope', {
+ type: 'org',
+ scope: { id: 'global', type: 'global' },
+ });
+ this.server.create('auth-method', {
+ scope: instances.scopes.org
+ }, 'withAccountsAndUsers');
+ instances.user = this.server.db.users[0];
+ accountsCount = instances.user.accountIds.length;
+ urls.users = `/scopes/${instances.scopes.org.id}/users`;
+ urls.user = `${urls.users}/${instances.user.id}`;
+ urls.accounts = `${urls.user}/accounts`;
+ urls.addAccounts = `${urls.user}/add-accounts`;
+ });
+
+ test('visiting user accounts', async function (assert) {
+ assert.expect(2);
+ await visit(urls.accounts);
+ await a11yAudit();
+ assert.equal(currentURL(), urls.accounts);
+ assert.equal(findAll('tbody tr').length, accountsCount);
+ });
+
+ test('can remove a account', async function (assert) {
+ assert.expect(2);
+ await visit(urls.accounts);
+ assert.equal(findAll('tbody tr').length, accountsCount);
+ await click('tbody tr .rose-dropdown-button-danger');
+ assert.equal(findAll('tbody tr').length, accountsCount - 1);
+ });
+
+ test('shows error message on account remove', async function (assert) {
+ assert.expect(2);
+ this.server.post('/users/:idMethod', () => {
+ return new Response(
+ 400,
+ {},
+ {
+ status: 400,
+ code: 'invalid_argument',
+ message: 'The request was invalid.',
+ details: {},
+ }
+ );
+ });
+ await visit(urls.accounts);
+ assert.equal(findAll('tbody tr').length, accountsCount);
+ await click('tbody tr .rose-dropdown-button-danger');
+ assert.ok(find('[role="alert"]'));
+ });
+
+ // test('visiting account add accounts', async function(assert) {
+ // assert.expect(1);
+ // await visit(urls.addAccounts);
+ // await a11yAudit();
+ // assert.equal(currentURL(), urls.addAccounts);
+ // });
+ //
+ // test('select and save accounts to add', async function (assert) {
+ // assert.expect(3);
+ // instances.user.update({ accountIds: [] });
+ // await visit(urls.accounts);
+ // assert.equal(findAll('tbody tr').length, 0);
+ // await click('.rose-layout-page-actions a')
+ // assert.equal(currentURL(), urls.addAccounts);
+ // await click('tbody label');
+ // await click('form [type="submit"]');
+ // await visit(urls.accounts);
+ // assert.equal(findAll('tbody tr').length, 1);
+ // });
+ //
+ // test('select and cancel accounts to add', async function (assert) {
+ // assert.expect(4);
+ // await visit(urls.accounts);
+ // assert.equal(findAll('tbody tr').length, accountsCount);
+ // await click('tbody tr .rose-dropdown-button-danger');
+ // assert.equal(findAll('tbody tr').length, accountsCount - 1);
+ // await click('.rose-layout-page-actions a')
+ // assert.equal(currentURL(), urls.addAccounts);
+ // await click('tbody label');
+ // await click('form [type="button"]');
+ // await visit(urls.accounts);
+ // assert.equal(findAll('tbody tr').length, accountsCount - 1);
+ // });
+ //
+ // test('shows error message on account add', async function (assert) {
+ // assert.expect(1);
+ // this.server.post('/users/:idMethod', () => {
+ // return new Response(
+ // 400,
+ // {},
+ // {
+ // status: 400,
+ // code: 'invalid_argument',
+ // message: 'The request was invalid.',
+ // details: {},
+ // }
+ // );
+ // });
+ // instances.user.update({ accountIds: [] });
+ // await visit(urls.addAccounts);
+ // await click('tbody label');
+ // await click('form [type="submit"]');
+ // assert.ok(find('[role="alert"]'));
+ // });
+});
diff --git a/ui/core/tests/unit/routes/scopes/scope/users/user/accounts-test.js b/ui/core/tests/unit/routes/scopes/scope/users/user/accounts-test.js
new file mode 100644
index 000000000..a98f97d71
--- /dev/null
+++ b/ui/core/tests/unit/routes/scopes/scope/users/user/accounts-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | scopes/scope/users/user/accounts', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:scopes/scope/users/user/accounts');
+ assert.ok(route);
+ });
+});
diff --git a/ui/core/translations/form/en-us.yaml b/ui/core/translations/form/en-us.yaml
index ed2e1e160..7bbf5c7bc 100644
--- a/ui/core/translations/form/en-us.yaml
+++ b/ui/core/translations/form/en-us.yaml
@@ -10,14 +10,14 @@ type:
label: Type
help: The type of the resource, to help differentiate schemas
login_name:
+ label: Login Name
+username:
label: Username
- help: The username for the account
set_password:
label: Password
- help: Create a new password for the account
+ help: Create a new password
password:
label: Password
- help: The password for the account
grant:
label: Grant
help: A permissions grant string for a role
diff --git a/ui/core/translations/resources/en-us.yaml b/ui/core/translations/resources/en-us.yaml
index fb595f18d..dd1b7848d 100644
--- a/ui/core/translations/resources/en-us.yaml
+++ b/ui/core/translations/resources/en-us.yaml
@@ -122,6 +122,14 @@ user:
messages:
welcome:
title: Welcome to Users
+ accounts:
+ title: Accounts
+ description: Users may be associated with any number of accounts.
+ add-accounts:
+ title: Add Accounts
+ description: Select accounts to associate with this user.
+ actions:
+ add-accounts: Add Accounts
role:
title: Role
title_plural: Roles
@@ -180,4 +188,4 @@ target:
description: No hosts sets available to add to target.
add:
title: Add Host Sets
- description: Select host sets to assign to this target.
\ No newline at end of file
+ description: Select host sets to assign to this target.
From 77940968ac8b5703342dc73a359892c28dd12964 Mon Sep 17 00:00:00 2001
From: Randall Morey
Date: Wed, 30 Sep 2020 11:32:25 -0400
Subject: [PATCH 03/13] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20user=20add-a?=
=?UTF-8?q?ccounts=20flow?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../form/target/add-host-sets/index.hbs | 4 +-
.../form/user/add-accounts/index.hbs | 56 +++++++++
.../form/user/add-accounts/index.js | 53 +++++++++
ui/core/app/router.js | 1 +
.../scopes/scope/users/user/add-accounts.js | 90 ++++++++++++++
.../scopes/scope/users/user/-actions.hbs | 3 +
.../scopes/scope/users/user/add-accounts.hbs | 25 ++++
.../scope/users/user/add-accounts/-header.hbs | 2 +
.../tests/acceptance/users/accounts-test.js | 110 +++++++++---------
.../components/form/user/add-accounts-test.js | 12 ++
.../scope/users/user/add-accounts-test.js | 11 ++
ui/core/translations/resources/en-us.yaml | 3 +
12 files changed, 313 insertions(+), 57 deletions(-)
create mode 100644 ui/core/app/components/form/user/add-accounts/index.hbs
create mode 100644 ui/core/app/components/form/user/add-accounts/index.js
create mode 100644 ui/core/app/routes/scopes/scope/users/user/add-accounts.js
create mode 100644 ui/core/app/templates/scopes/scope/users/user/add-accounts.hbs
create mode 100644 ui/core/app/templates/scopes/scope/users/user/add-accounts/-header.hbs
create mode 100644 ui/core/tests/integration/components/form/user/add-accounts-test.js
create mode 100644 ui/core/tests/unit/routes/scopes/scope/users/user/add-accounts-test.js
diff --git a/ui/core/app/components/form/target/add-host-sets/index.hbs b/ui/core/app/components/form/target/add-host-sets/index.hbs
index fa02412bb..545f45f91 100644
--- a/ui/core/app/components/form/target/add-host-sets/index.hbs
+++ b/ui/core/app/components/form/target/add-host-sets/index.hbs
@@ -18,7 +18,7 @@
{{t 'form.id.label'}}
{{t 'form.name.label'}}
{{t 'form.type.label'}}
- {{t 'resources.host-catalog.title_plural'}}
+ {{t 'resources.host-catalog.title'}}
@@ -57,4 +57,4 @@
-{{/unless}}
\ No newline at end of file
+{{/unless}}
diff --git a/ui/core/app/components/form/user/add-accounts/index.hbs b/ui/core/app/components/form/user/add-accounts/index.hbs
new file mode 100644
index 000000000..f3bfed288
--- /dev/null
+++ b/ui/core/app/components/form/user/add-accounts/index.hbs
@@ -0,0 +1,56 @@
+{{#if this.hasAvailableAccounts}}
+
+
+
+
+
+
+
+ {{t 'form.id.label'}}
+ {{t 'form.username.label'}}
+ {{t 'resources.auth-method.title'}}
+
+
+
+ {{#each this.filteredAccounts as |account|}}
+
+
+
+
+ {{account.username}}
+
+ {{account.auth_method_id}}
+
+
+ {{/each}}
+
+
+
+
+{{/if}}
+
+{{#unless this.hasAvailableAccounts}}
+
+
+
+ {{t "resources.user.messages.no-accounts.description"}}
+
+
+
+ {{t "actions.back"}}
+
+
+
+{{/unless}}
diff --git a/ui/core/app/components/form/user/add-accounts/index.js b/ui/core/app/components/form/user/add-accounts/index.js
new file mode 100644
index 000000000..b5f49e947
--- /dev/null
+++ b/ui/core/app/components/form/user/add-accounts/index.js
@@ -0,0 +1,53 @@
+import Component from '@glimmer/component';
+import { computed, action } from '@ember/object';
+import { A } from '@ember/array';
+
+export default class FormUserAddAccountsComponent extends Component {
+ // =properties
+
+ /**
+ * Array of selected account IDs.
+ * @type {EmberArray}
+ */
+ selectedAccountIDs = A();
+
+ /**
+ * Checks for unassigned accounts.
+ * @param {[AccountModel]} filteredAccounts
+ * @type {boolean}
+ */
+ @computed('filteredAccounts')
+ get hasAvailableAccounts() {
+ return this.filteredAccounts.length > 0;
+ }
+
+ /**
+ * Accounts not already added to the user.
+ * @type {[AccountModel]}
+ */
+ @computed('args.{accounts.[],model.account_ids.[]}')
+ get filteredAccounts() {
+ // Get IDs for accounts already added to the current user
+ const alreadyAddedAccountIDs = this.args.model.account_ids;
+ const notAddedAccounts = this.args.accounts.filter(
+ ({ id }) => !alreadyAddedAccountIDs.includes(id)
+ );
+ return notAddedAccounts;
+ }
+
+ // =actions
+
+ @action
+ toggleAccount(account) {
+ if (!this.selectedAccountIDs.includes(account.id)) {
+ this.selectedAccountIDs.addObject(account.id);
+ } else {
+ this.selectedAccountIDs.removeObject(account.id);
+ }
+ }
+
+ @action
+ submit(fn) {
+ fn(this.selectedAccountIDs);
+ }
+}
diff --git a/ui/core/app/router.js b/ui/core/app/router.js
index 8142aa85a..748ad73a6 100644
--- a/ui/core/app/router.js
+++ b/ui/core/app/router.js
@@ -60,6 +60,7 @@ Router.map(function () {
this.route('users', function () {
this.route('user', { path: ':user_id' }, function () {
this.route('accounts');
+ this.route('add-accounts');
});
this.route('new');
});
diff --git a/ui/core/app/routes/scopes/scope/users/user/add-accounts.js b/ui/core/app/routes/scopes/scope/users/user/add-accounts.js
new file mode 100644
index 000000000..bdb7b0e9c
--- /dev/null
+++ b/ui/core/app/routes/scopes/scope/users/user/add-accounts.js
@@ -0,0 +1,90 @@
+import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
+import { action } from '@ember/object';
+import { all } from 'rsvp';
+import loading from 'ember-loading/decorator';
+
+export default class ScopesScopeUsersUserAddAccountsRoute extends Route {
+ // =services
+
+ @service intl;
+ @service notify;
+
+ // =methods
+
+ /**
+ * Emtpy out any previously loaded acconuts.
+ */
+ beforeModel() {
+ this.store.unloadAll('account');
+ }
+
+ /**
+ * Returns the current target, all host catalogs, and all host sets.
+ * @return {{target: TargetModel, hostCatalogs: [HostCatalogModel], hostSets: [HostSetModel]}}
+ */
+ async model() {
+ const user = this.modelFor('scopes.scope.users.user');
+ const { id: scope_id } = this.modelFor('scopes.scope');
+ const authMethods = await this.store.query('auth-method', { scope_id });
+ await all(
+ authMethods.map(({ id: auth_method_id }) =>
+ this.store.query('account', { auth_method_id })
+ )
+ );
+ const accounts = this.store.peekAll('account');
+ return { user, authMethods, accounts };
+ }
+
+ /**
+ * Renders the route-set specific page sections
+ * @override
+ */
+ renderTemplate() {
+ super.renderTemplate(...arguments);
+
+ this.render('scopes/scope/users/user/add-accounts/-header', {
+ into: 'scopes/scope/users/user',
+ outlet: 'header',
+ });
+
+ this.render('-empty', {
+ into: 'scopes/scope/users/user',
+ outlet: 'actions',
+ });
+
+ this.render('-empty', {
+ into: 'scopes/scope/users/user',
+ outlet: 'navigation',
+ });
+ }
+
+ // =actions
+
+ /**
+ * Adds accounts to the user and saves, replaces with the accounts index
+ * route, and notifies the user of success or error.
+ * @param {UserModel} user
+ * @param {[string]} accountIDs
+ */
+ @action
+ @loading
+ async addAccounts(user, accountIDs) {
+ try {
+ await user.addAccounts(accountIDs);
+ await this.replaceWith('scopes.scope.users.user.accounts');
+ this.notify.success(this.intl.t('notifications.add-success'));
+ } catch (error) {
+ // TODO: replace with translated strings
+ this.notify.error(error.message, { closeAfter: null });
+ }
+ }
+
+ /**
+ * Redirect to user accounts as if nothing ever happened.
+ */
+ @action
+ cancel() {
+ this.replaceWith('scopes.scope.users.user.accounts');
+ }
+}
diff --git a/ui/core/app/templates/scopes/scope/users/user/-actions.hbs b/ui/core/app/templates/scopes/scope/users/user/-actions.hbs
index b72d4c322..c5de304c1 100644
--- a/ui/core/app/templates/scopes/scope/users/user/-actions.hbs
+++ b/ui/core/app/templates/scopes/scope/users/user/-actions.hbs
@@ -1,4 +1,7 @@
+
+ {{t "resources.user.actions.add-accounts"}}
+
+{{/if}}
+
+{{#unless @model.accounts}}
+
+
+
+ {{t "resources.user.messages.no-accounts.description"}}
+
+
+
+ {{t "actions.back"}}
+
+
+
+{{/unless}}
diff --git a/ui/core/app/templates/scopes/scope/users/user/add-accounts/-header.hbs b/ui/core/app/templates/scopes/scope/users/user/add-accounts/-header.hbs
new file mode 100644
index 000000000..d9a819fe8
--- /dev/null
+++ b/ui/core/app/templates/scopes/scope/users/user/add-accounts/-header.hbs
@@ -0,0 +1,2 @@
+{{t "resources.user.messages.add-accounts.title"}}
+{{t "resources.user.messages.add-accounts.description"}}
diff --git a/ui/core/tests/acceptance/users/accounts-test.js b/ui/core/tests/acceptance/users/accounts-test.js
index 0dead76e1..8bcaa951a 100644
--- a/ui/core/tests/acceptance/users/accounts-test.js
+++ b/ui/core/tests/acceptance/users/accounts-test.js
@@ -41,7 +41,7 @@ module('Acceptance | users | accounts', function (hooks) {
this.server.create('auth-method', {
scope: instances.scopes.org
}, 'withAccountsAndUsers');
- instances.user = this.server.db.users[0];
+ instances.user = this.server.schema.users.all().models[0];
accountsCount = instances.user.accountIds.length;
urls.users = `/scopes/${instances.scopes.org.id}/users`;
urls.user = `${urls.users}/${instances.user.id}`;
@@ -85,58 +85,58 @@ module('Acceptance | users | accounts', function (hooks) {
assert.ok(find('[role="alert"]'));
});
- // test('visiting account add accounts', async function(assert) {
- // assert.expect(1);
- // await visit(urls.addAccounts);
- // await a11yAudit();
- // assert.equal(currentURL(), urls.addAccounts);
- // });
- //
- // test('select and save accounts to add', async function (assert) {
- // assert.expect(3);
- // instances.user.update({ accountIds: [] });
- // await visit(urls.accounts);
- // assert.equal(findAll('tbody tr').length, 0);
- // await click('.rose-layout-page-actions a')
- // assert.equal(currentURL(), urls.addAccounts);
- // await click('tbody label');
- // await click('form [type="submit"]');
- // await visit(urls.accounts);
- // assert.equal(findAll('tbody tr').length, 1);
- // });
- //
- // test('select and cancel accounts to add', async function (assert) {
- // assert.expect(4);
- // await visit(urls.accounts);
- // assert.equal(findAll('tbody tr').length, accountsCount);
- // await click('tbody tr .rose-dropdown-button-danger');
- // assert.equal(findAll('tbody tr').length, accountsCount - 1);
- // await click('.rose-layout-page-actions a')
- // assert.equal(currentURL(), urls.addAccounts);
- // await click('tbody label');
- // await click('form [type="button"]');
- // await visit(urls.accounts);
- // assert.equal(findAll('tbody tr').length, accountsCount - 1);
- // });
- //
- // test('shows error message on account add', async function (assert) {
- // assert.expect(1);
- // this.server.post('/users/:idMethod', () => {
- // return new Response(
- // 400,
- // {},
- // {
- // status: 400,
- // code: 'invalid_argument',
- // message: 'The request was invalid.',
- // details: {},
- // }
- // );
- // });
- // instances.user.update({ accountIds: [] });
- // await visit(urls.addAccounts);
- // await click('tbody label');
- // await click('form [type="submit"]');
- // assert.ok(find('[role="alert"]'));
- // });
+ test('visiting account add accounts', async function(assert) {
+ assert.expect(1);
+ await visit(urls.addAccounts);
+ await a11yAudit();
+ assert.equal(currentURL(), urls.addAccounts);
+ });
+
+ test('select and save accounts to add', async function (assert) {
+ assert.expect(3);
+ instances.user.update({ accountIds: [] });
+ await visit(urls.accounts);
+ assert.equal(findAll('tbody tr').length, 0);
+ await click('.rose-layout-page-actions a')
+ assert.equal(currentURL(), urls.addAccounts);
+ await click('tbody label');
+ await click('form [type="submit"]');
+ await visit(urls.accounts);
+ assert.equal(findAll('tbody tr').length, 1);
+ });
+
+ test('select and cancel accounts to add', async function (assert) {
+ assert.expect(4);
+ await visit(urls.accounts);
+ assert.equal(findAll('tbody tr').length, accountsCount);
+ await click('tbody tr .rose-dropdown-button-danger');
+ assert.equal(findAll('tbody tr').length, accountsCount - 1);
+ await click('.rose-layout-page-actions a')
+ assert.equal(currentURL(), urls.addAccounts);
+ await click('tbody label');
+ await click('form [type="button"]');
+ await visit(urls.accounts);
+ assert.equal(findAll('tbody tr').length, accountsCount - 1);
+ });
+
+ test('shows error message on account add', async function (assert) {
+ assert.expect(1);
+ this.server.post('/users/:idMethod', () => {
+ return new Response(
+ 400,
+ {},
+ {
+ status: 400,
+ code: 'invalid_argument',
+ message: 'The request was invalid.',
+ details: {},
+ }
+ );
+ });
+ instances.user.update({ accountIds: [] });
+ await visit(urls.addAccounts);
+ await click('tbody label');
+ await click('form [type="submit"]');
+ assert.ok(find('[role="alert"]'));
+ });
});
diff --git a/ui/core/tests/integration/components/form/user/add-accounts-test.js b/ui/core/tests/integration/components/form/user/add-accounts-test.js
new file mode 100644
index 000000000..ba96e4dba
--- /dev/null
+++ b/ui/core/tests/integration/components/form/user/add-accounts-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+// import { render } from '@ember/test-helpers';
+// import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | form/user/add-accounts', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function(assert) {
+ assert.expect(0);
+ });
+});
diff --git a/ui/core/tests/unit/routes/scopes/scope/users/user/add-accounts-test.js b/ui/core/tests/unit/routes/scopes/scope/users/user/add-accounts-test.js
new file mode 100644
index 000000000..2aac18540
--- /dev/null
+++ b/ui/core/tests/unit/routes/scopes/scope/users/user/add-accounts-test.js
@@ -0,0 +1,11 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Route | scopes/scope/users/user/add-accounts', function(hooks) {
+ setupTest(hooks);
+
+ test('it exists', function(assert) {
+ let route = this.owner.lookup('route:scopes/scope/users/user/add-accounts');
+ assert.ok(route);
+ });
+});
diff --git a/ui/core/translations/resources/en-us.yaml b/ui/core/translations/resources/en-us.yaml
index dd1b7848d..81ade9e0f 100644
--- a/ui/core/translations/resources/en-us.yaml
+++ b/ui/core/translations/resources/en-us.yaml
@@ -128,6 +128,9 @@ user:
add-accounts:
title: Add Accounts
description: Select accounts to associate with this user.
+ no-accounts:
+ title: No Accounts Available
+ description: There are no accounts available to add to this user.
actions:
add-accounts: Add Accounts
role:
From ce257be8a7c247a2e5055c0fd8a340904a0441e1 Mon Sep 17 00:00:00 2001
From: Randall Morey
Date: Wed, 30 Sep 2020 11:35:49 -0400
Subject: [PATCH 04/13] chore: add breadcrumbs
---
.../scopes/scope/users/user/add-accounts.js | 17 +++++++++++++++++
.../scope/users/user/add-accounts-test.js | 12 ++++++++++++
2 files changed, 29 insertions(+)
create mode 100644 ui/core/app/controllers/scopes/scope/users/user/add-accounts.js
create mode 100644 ui/core/tests/unit/controllers/scopes/scope/users/user/add-accounts-test.js
diff --git a/ui/core/app/controllers/scopes/scope/users/user/add-accounts.js b/ui/core/app/controllers/scopes/scope/users/user/add-accounts.js
new file mode 100644
index 000000000..de02366b1
--- /dev/null
+++ b/ui/core/app/controllers/scopes/scope/users/user/add-accounts.js
@@ -0,0 +1,17 @@
+import Controller from '@ember/controller';
+import { inject as service } from '@ember/service';
+
+export default class ScopesScopeUsersUserAddAccountsController extends Controller {
+ // =services
+
+ @service intl;
+
+ // =attributes
+
+ /**
+ * @type {string}
+ */
+ get breadCrumb() {
+ return this.intl.t('resources.user.messages.add-accounts.title');
+ }
+}
diff --git a/ui/core/tests/unit/controllers/scopes/scope/users/user/add-accounts-test.js b/ui/core/tests/unit/controllers/scopes/scope/users/user/add-accounts-test.js
new file mode 100644
index 000000000..a71b3d2e0
--- /dev/null
+++ b/ui/core/tests/unit/controllers/scopes/scope/users/user/add-accounts-test.js
@@ -0,0 +1,12 @@
+import { module, test } from 'qunit';
+import { setupTest } from 'ember-qunit';
+
+module('Unit | Controller | scopes/scope/users/user/add-accounts', function(hooks) {
+ setupTest(hooks);
+
+ // Replace this with your real tests.
+ test('it exists', function(assert) {
+ let controller = this.owner.lookup('controller:scopes/scope/users/user/add-accounts');
+ assert.ok(controller);
+ });
+});
From da6192a3cd2704dc9f532ba80caa52820684f10d Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 12:18:12 -0400
Subject: [PATCH 05/13] feat: Make all ids copyable
---
ui/core/app/components/copyable/index.js | 1 -
ui/core/app/styles/app.scss | 3 ++-
.../scopes/scope/auth-methods/auth-method/-header.hbs | 4 +++-
.../auth-methods/auth-method/accounts/account/-header.hbs | 4 +++-
.../auth-method/accounts/account/set-password/-header.hbs | 4 +++-
.../scopes/scope/auth-methods/auth-method/accounts/index.hbs | 4 +++-
ui/core/app/templates/scopes/scope/auth-methods/index.hbs | 4 +++-
ui/core/app/templates/scopes/scope/groups/group/-header.hbs | 4 +++-
ui/core/app/templates/scopes/scope/groups/group/members.hbs | 4 +++-
ui/core/app/templates/scopes/scope/groups/index.hbs | 4 +++-
.../projects/project/host-catalogs/host-catalog/-header.hbs | 4 +++-
.../project/host-catalogs/host-catalog/host-sets/-header.hbs | 4 +++-
.../host-catalogs/host-catalog/host-sets/host-set/hosts.hbs | 4 +++-
.../project/host-catalogs/host-catalog/host-sets/index.hbs | 4 +++-
.../project/host-catalogs/host-catalog/hosts/-header.hbs | 4 +++-
.../project/host-catalogs/host-catalog/hosts/index.hbs | 4 +++-
.../scopes/scope/projects/project/host-catalogs/index.hbs | 4 +++-
ui/core/app/templates/scopes/scope/projects/project/index.hbs | 4 +++-
.../scopes/scope/projects/project/sessions/index.hbs | 4 +++-
.../templates/scopes/scope/projects/project/targets/index.hbs | 4 +++-
.../scopes/scope/projects/project/targets/target/-header.hbs | 4 +++-
.../scope/projects/project/targets/target/host-sets.hbs | 4 +++-
ui/core/app/templates/scopes/scope/roles/index.hbs | 4 +++-
ui/core/app/templates/scopes/scope/roles/role/-header.hbs | 4 +++-
.../app/templates/scopes/scope/roles/role/grants/-header.hbs | 4 +++-
ui/core/app/templates/scopes/scope/roles/role/principals.hbs | 4 +++-
.../templates/scopes/scope/roles/role/principals/-header.hbs | 4 +++-
ui/core/app/templates/scopes/scope/users/index.hbs | 4 +++-
ui/core/app/templates/scopes/scope/users/user/index.hbs | 4 +++-
29 files changed, 83 insertions(+), 29 deletions(-)
diff --git a/ui/core/app/components/copyable/index.js b/ui/core/app/components/copyable/index.js
index 01dcad838..cefc032fa 100644
--- a/ui/core/app/components/copyable/index.js
+++ b/ui/core/app/components/copyable/index.js
@@ -16,7 +16,6 @@ export default class CopyableComponent extends Component {
icon = 'copy-action';
@tracked text;
- @tracked clipboard;
/**
* A Ember Concurrency-based task that updates copy icon to a success state
diff --git a/ui/core/app/styles/app.scss b/ui/core/app/styles/app.scss
index 9e72b055f..dfe9fe1f9 100644
--- a/ui/core/app/styles/app.scss
+++ b/ui/core/app/styles/app.scss
@@ -82,5 +82,6 @@
}
.copyable .copyable-button {
- padding: 0rem;
+ padding: 0 sizing.rems(xxs);
+ margin: 0;
}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs
index ba94f66be..0748ed7b8 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.auth-method.title"}}
{{t "resources.auth-method.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs
index 938c5fedb..c7a1ec474 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs
@@ -1,2 +1,4 @@
{{t "resources.account.title"}}
-{{@model.id}}
\ No newline at end of file
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs
index 5c5ee4dd4..1805683a2 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.account.title"}}
{{t 'resources.account.messages.set-password.description'}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
index 81b93da9c..d399eb1d8 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
@@ -24,7 +24,9 @@
{{account.username}}
- {{account.id}}
+
+ {{account.id}}
+
{{/each}}
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 e1c23f96f..26027d51b 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
@@ -46,7 +46,9 @@
- {{authMethod.id}}
+
+ {{authMethod.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/groups/group/-header.hbs b/ui/core/app/templates/scopes/scope/groups/group/-header.hbs
index ac1e772a0..a876cafac 100644
--- a/ui/core/app/templates/scopes/scope/groups/group/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/group/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.group.title"}}
{{t "resources.group.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/groups/group/members.hbs b/ui/core/app/templates/scopes/scope/groups/group/members.hbs
index 0b6dee825..ce5eee601 100644
--- a/ui/core/app/templates/scopes/scope/groups/group/members.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/group/members.hbs
@@ -17,7 +17,9 @@
{{member.displayName}}
- {{member.id}}
+
+ {{member.id}}
+
{{group.description}}
- {{group.id}}
+
+ {{group.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs
index 77e14a09b..8857383a2 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.host-catalog.title"}}
{{t "resources.host-catalog.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs
index 752eae74c..26afcea96 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.host-set.title"}}
{{t "resources.host-set.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs
index abc6852da..7b65efa26 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs
@@ -25,7 +25,9 @@
{{host.type}}
- {{host.id}}
+
+ {{host.id}}
+
- {{hostSet.id}}
+
+ {{hostSet.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs
index e8a7b9c8d..f0d679039 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.host.title"}}
{{t "resources.host.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs
index 3f1c23860..87ae8db1a 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs
@@ -27,7 +27,9 @@
- {{host.id}}
+
+ {{host.id}}
+
{{host.attributes.address}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs
index 578a59c4a..2f758b992 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs
@@ -47,7 +47,9 @@
- {{hostCatalog.id}}
+
+ {{hostCatalog.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/index.hbs
index 79c5e6e41..58395a683 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/index.hbs
@@ -7,7 +7,9 @@
{{t "resources.project.title"}}
{{t "resources.project.description"}}
- {{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs
index a34ceb077..b4e5d3e4f 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs
@@ -28,7 +28,9 @@
{{#each @model as |sessionAggregate|}}
- {{sessionAggregate.session.id}}
+
+ {{sessionAggregate.session.id}}
+
{{sessionAggregate.user.displayName}}
{{sessionAggregate.target.displayName}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs
index d6e45da25..ff84ac48e 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs
@@ -51,7 +51,9 @@
{{/if}}
- {{target.id}}
+
+ {{target.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs
index 280737623..b96093e47 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.target.title"}}
{{t "resources.target.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs b/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs
index 827793ccd..e03aa2610 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs
@@ -22,7 +22,9 @@
{{t (concat 'resources.host-set.types.' hostSet.model.type)}}
- {{hostSet.model.id}}
+
+ {{hostSet.model.id}}
+
{{role.description}}
- {{role.id}}
+
+ {{role.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/roles/role/-header.hbs b/ui/core/app/templates/scopes/scope/roles/role/-header.hbs
index ccad156d5..926771735 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.role.title"}}
{{t "resources.role.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs b/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs
index aa96ca797..ccea2b2d0 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs
@@ -1,3 +1,5 @@
{{t "resources.role.title"}}
{{t "resources.role.grant.description"}}
-{{@model.id}}
+
+ {{@model.id}}
+
\ No newline at end of file
diff --git a/ui/core/app/templates/scopes/scope/roles/role/principals.hbs b/ui/core/app/templates/scopes/scope/roles/role/principals.hbs
index 73ac90715..58041d4a0 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/principals.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/principals.hbs
@@ -21,7 +21,9 @@
{{t (concat 'resources.role.principal.types.' principal.type)}}
- {{principal.model.id}}
+
+ {{principal.model.id}}
+
{{t "resources.role.title"}}
{{t "resources.role.principal.description"}}
-{{@model.role.id}}
+
+ {{@model.role.id}}
+
diff --git a/ui/core/app/templates/scopes/scope/users/index.hbs b/ui/core/app/templates/scopes/scope/users/index.hbs
index 26458d273..50bcd7b74 100644
--- a/ui/core/app/templates/scopes/scope/users/index.hbs
+++ b/ui/core/app/templates/scopes/scope/users/index.hbs
@@ -41,7 +41,9 @@
{{user.description}}
- {{user.id}}
+
+ {{user.id}}
+
{{/each}}
diff --git a/ui/core/app/templates/scopes/scope/users/user/index.hbs b/ui/core/app/templates/scopes/scope/users/user/index.hbs
index 35db006e9..7f9218f1b 100644
--- a/ui/core/app/templates/scopes/scope/users/user/index.hbs
+++ b/ui/core/app/templates/scopes/scope/users/user/index.hbs
@@ -7,7 +7,9 @@
{{t "resources.user.title"}}
{{t "resources.user.description"}}
- {{@model.id}}
+
+ {{@model.id}}
+
From 2600411c700b29d0c88cf73a0cb4241aed0249b1 Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 12:57:30 -0400
Subject: [PATCH 06/13] refactor: Fix sass lint errors in ui/core
---
ui/core/app/styles/_notify.scss | 8 ++++----
ui/core/app/styles/app.scss | 25 +++++++++++++------------
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/ui/core/app/styles/_notify.scss b/ui/core/app/styles/_notify.scss
index 438f0950c..784bc746f 100644
--- a/ui/core/app/styles/_notify.scss
+++ b/ui/core/app/styles/_notify.scss
@@ -61,19 +61,19 @@
.ember-notify-show {
-webkit-animation-duration: 500ms;
-webkit-animation-name: ember-notify-show;
- -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -webkit-animation-timing-function: cubic-bezier(.175, .885, .32, 1.275);
animation-duration: 500ms;
animation-name: ember-notify-show;
- animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ animation-timing-function: cubic-bezier(.175, .885, .32, 1.275);
}
.ember-notify-hide {
-webkit-animation-duration: 250ms;
-webkit-animation-name: ember-notify-hide;
- -webkit-animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
+ -webkit-animation-timing-function: cubic-bezier(.6, -.28, .735, .045);
animation-duration: 250ms;
animation-name: ember-notify-hide;
- animation-timing-function: cubic-bezier(0.6, -0.28, 0.735, 0.045);
+ animation-timing-function: cubic-bezier(.6, -.28, .735, .045);
&:hover {
-moz-animation-play-state: paused;
diff --git a/ui/core/app/styles/app.scss b/ui/core/app/styles/app.scss
index 9e72b055f..8aad37e0b 100644
--- a/ui/core/app/styles/app.scss
+++ b/ui/core/app/styles/app.scss
@@ -61,17 +61,16 @@
&.loading {
&::after {
- content: " ";
- position: absolute;
- top: 100%;
- left: 0;
- right: 0;
- height: 3px;
-
- background: repeating-linear-gradient(to right, #fff, #fff, var(--info), #fff, #fff);
- background-size: 200% auto;
- background-position: 0 100%;
animation: gradient 1s linear infinite;
+ background: repeating-linear-gradient(to right, var(--white), var(--white), var(--info), var(--white), var(--white));
+ background-position: 0 100%;
+ background-size: 200% auto;
+ content: ' ';
+ height: 3px;
+ left: 0;
+ position: absolute;
+ right: 0;
+ top: 100%;
@keyframes gradient {
0% { background-position: 0 0; }
@@ -81,6 +80,8 @@
}
}
-.copyable .copyable-button {
- padding: 0rem;
+.copyable {
+ .copyable-button {
+ padding: 0;
+ }
}
From 8bf3c295a6381aadd43afc3fe3e1ca0ca26ca114 Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 14:12:34 -0400
Subject: [PATCH 07/13] feat: Add footer section to global layout in
addons/rose
---
.../components/rose/layout/global/index.hbs | 1 +
.../rose/layout/global/index.stories.mdx | 18 +++++++++---------
.../components/rose/layout/global-test.js | 7 +++++++
3 files changed, 17 insertions(+), 9 deletions(-)
diff --git a/addons/rose/addon/components/rose/layout/global/index.hbs b/addons/rose/addon/components/rose/layout/global/index.hbs
index bfa2c8e75..373f70531 100644
--- a/addons/rose/addon/components/rose/layout/global/index.hbs
+++ b/addons/rose/addon/components/rose/layout/global/index.hbs
@@ -2,5 +2,6 @@
{{yield (hash
header=(component "rose/anonymous" tagName="header" class="rose-layout-global-header")
body=(component "rose/anonymous" class="rose-layout-global-body")
+ footer=(component "rose/anonymous" class="rose-layout-global-footer")
)}}
diff --git a/addons/rose/addon/components/rose/layout/global/index.stories.mdx b/addons/rose/addon/components/rose/layout/global/index.stories.mdx
index 9b8e34ea4..22cb6b8e6 100644
--- a/addons/rose/addon/components/rose/layout/global/index.stories.mdx
+++ b/addons/rose/addon/components/rose/layout/global/index.stories.mdx
@@ -1,29 +1,29 @@
import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
import { hbs } from 'ember-cli-htmlbars';
-import { action } from '@storybook/addon-actions';
-import { text, boolean, select } from '@storybook/addon-knobs';
# Layout|Global
-A top-level layout/positioning component that allows two distinct sections to
-be configured: header and body.
+A top-level layout/positioning component that allows three distinct sections to
+be configured: header, body, and footer.
-```htmlbars
+```html
+
```
{{
template: hbs`
-
- Header
- Body
-
+
+ Header
+ Body
+ Footer
+
`,
}}
diff --git a/addons/rose/tests/integration/components/rose/layout/global-test.js b/addons/rose/tests/integration/components/rose/layout/global-test.js
index 2e6b91039..aa87f074b 100644
--- a/addons/rose/tests/integration/components/rose/layout/global-test.js
+++ b/addons/rose/tests/integration/components/rose/layout/global-test.js
@@ -30,4 +30,11 @@ module('Integration | Component | rose/layout/global', function (hooks) {
`);
assert.ok(find('.rose-layout-global-body'));
});
+
+ test('it renders with footer', async function (assert) {
+ await render(hbs`
+
+ `);
+ assert.ok(find('.rose-layout-global-footer'));
+ });
});
From 56b99a99a044dc5eb494f565740d0631070654e9 Mon Sep 17 00:00:00 2001
From: Randall Morey
Date: Wed, 30 Sep 2020 14:15:32 -0400
Subject: [PATCH 08/13] chore: tweak button position, a11y, and add button text
---
ui/core/app/components/copyable/index.hbs | 5 +++--
ui/core/app/styles/app.scss | 10 +++++++---
.../templates/scopes/scope/projects/project/index.hbs | 6 +++++-
ui/core/translations/actions/en-us.yaml | 3 ++-
ui/core/translations/states/en-us.yaml | 1 +
5 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/ui/core/app/components/copyable/index.hbs b/ui/core/app/components/copyable/index.hbs
index 8d0a3df75..fc47d613c 100644
--- a/ui/core/app/components/copyable/index.hbs
+++ b/ui/core/app/components/copyable/index.hbs
@@ -1,7 +1,6 @@
{{#if this.isClipboardLibrarySupported}}
{{@text}}
+ title={{@buttonText}}
+ >{{@buttonText}}
{{else}}
{{yield}}
diff --git a/ui/core/app/styles/app.scss b/ui/core/app/styles/app.scss
index dfe9fe1f9..2cd923218 100644
--- a/ui/core/app/styles/app.scss
+++ b/ui/core/app/styles/app.scss
@@ -81,7 +81,11 @@
}
}
-.copyable .copyable-button {
- padding: 0 sizing.rems(xxs);
- margin: 0;
+.copyable {
+ .copyable-button {
+ position: relative;
+ top: -2px;
+ padding: 0 sizing.rems(xxs);
+ margin: 0;
+ }
}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/index.hbs
index 58395a683..0de5bb65c 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/index.hbs
@@ -7,7 +7,11 @@
{{t "resources.project.title"}}
{{t "resources.project.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/translations/actions/en-us.yaml b/ui/core/translations/actions/en-us.yaml
index 7e7a9002a..9b1fa9751 100644
--- a/ui/core/translations/actions/en-us.yaml
+++ b/ui/core/translations/actions/en-us.yaml
@@ -7,6 +7,7 @@ save: Save
manage: Manage
help: Need help?
back: Back
+copy-to-clipboard: Copy to Clipboard
authenticate: Authenticate
deauthenticate: Deauthenticate
choose-org: Choose Scope
@@ -27,4 +28,4 @@ add-members: Add Members
add-hosts: Add Hosts
set-password: Set Password
change-password: Change Password
-edit-form: Edit Form
\ No newline at end of file
+edit-form: Edit Form
diff --git a/ui/core/translations/states/en-us.yaml b/ui/core/translations/states/en-us.yaml
index 585ed6a26..96b1fd92c 100644
--- a/ui/core/translations/states/en-us.yaml
+++ b/ui/core/translations/states/en-us.yaml
@@ -2,3 +2,4 @@ info: Info
success: Success
warning: Warning
error: Error
+copied: Copied
From af2710f6c47979832188ca8eac657446dc816600 Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 17:03:13 -0400
Subject: [PATCH 09/13] feat: Add global footer
---
.../components/rose/footer/brand/index.hbs | 12 +++++
.../rose/footer/copyright/index.hbs | 11 ++++
.../components/rose/footer/copyright/index.js | 8 +++
.../addon/components/rose/footer/index.hbs | 11 ++++
.../components/rose/footer/index.stories.mdx | 42 +++++++++++++++
.../rose/footer/nav/external-link/index.hbs | 7 +++
.../components/rose/footer/nav/index.hbs | 5 ++
.../components/rose/footer/product/index.hbs | 11 ++++
.../addon/styles/rose/components/_index.scss | 1 +
.../styles/rose/components/footer/_brand.scss | 14 +++++
.../rose/components/footer/_copyright.scss | 14 +++++
.../components/footer/_external-link.scss | 9 ++++
.../styles/rose/components/footer/_index.scss | 18 +++++++
.../styles/rose/components/footer/_nav.scss | 9 ++++
.../rose/components/footer/_product.scss | 11 ++++
addons/rose/app/components/rose/footer.js | 1 +
.../rose/app/components/rose/footer/brand.js | 1 +
.../app/components/rose/footer/copyright.js | 1 +
addons/rose/app/components/rose/footer/nav.js | 1 +
.../rose/footer/nav/external-link.js | 1 +
.../app/components/rose/footer/product.js | 1 +
.../components/rose/footer-test.js | 51 +++++++++++++++++++
.../components/rose/footer/brand-test.js | 15 ++++++
.../components/rose/footer/copyright-test.js | 20 ++++++++
.../components/rose/footer/nav-test.js | 24 +++++++++
.../rose/footer/nav/external-link-test.js | 15 ++++++
.../components/rose/footer/product-test.js | 22 ++++++++
ui/core/app/templates/application.hbs | 11 ++++
ui/core/translations/en-us.yaml | 9 +++-
29 files changed, 355 insertions(+), 1 deletion(-)
create mode 100644 addons/rose/addon/components/rose/footer/brand/index.hbs
create mode 100644 addons/rose/addon/components/rose/footer/copyright/index.hbs
create mode 100644 addons/rose/addon/components/rose/footer/copyright/index.js
create mode 100644 addons/rose/addon/components/rose/footer/index.hbs
create mode 100644 addons/rose/addon/components/rose/footer/index.stories.mdx
create mode 100644 addons/rose/addon/components/rose/footer/nav/external-link/index.hbs
create mode 100644 addons/rose/addon/components/rose/footer/nav/index.hbs
create mode 100644 addons/rose/addon/components/rose/footer/product/index.hbs
create mode 100644 addons/rose/addon/styles/rose/components/footer/_brand.scss
create mode 100644 addons/rose/addon/styles/rose/components/footer/_copyright.scss
create mode 100644 addons/rose/addon/styles/rose/components/footer/_external-link.scss
create mode 100644 addons/rose/addon/styles/rose/components/footer/_index.scss
create mode 100644 addons/rose/addon/styles/rose/components/footer/_nav.scss
create mode 100644 addons/rose/addon/styles/rose/components/footer/_product.scss
create mode 100644 addons/rose/app/components/rose/footer.js
create mode 100644 addons/rose/app/components/rose/footer/brand.js
create mode 100644 addons/rose/app/components/rose/footer/copyright.js
create mode 100644 addons/rose/app/components/rose/footer/nav.js
create mode 100644 addons/rose/app/components/rose/footer/nav/external-link.js
create mode 100644 addons/rose/app/components/rose/footer/product.js
create mode 100644 addons/rose/tests/integration/components/rose/footer-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/brand-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/copyright-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/nav-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/product-test.js
diff --git a/addons/rose/addon/components/rose/footer/brand/index.hbs b/addons/rose/addon/components/rose/footer/brand/index.hbs
new file mode 100644
index 000000000..27b91417f
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/brand/index.hbs
@@ -0,0 +1,12 @@
+
+
+ {{#if @logo}}
+ {{inline-svg @logo}}
+ {{/if}}
+
+
diff --git a/addons/rose/addon/components/rose/footer/copyright/index.hbs b/addons/rose/addon/components/rose/footer/copyright/index.hbs
new file mode 100644
index 000000000..47e582dcb
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/copyright/index.hbs
@@ -0,0 +1,11 @@
+
diff --git a/addons/rose/addon/components/rose/footer/copyright/index.js b/addons/rose/addon/components/rose/footer/copyright/index.js
new file mode 100644
index 000000000..a9068f750
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/copyright/index.js
@@ -0,0 +1,8 @@
+import Component from '@glimmer/component';
+
+export default class RoseFooterCopyrightComponent extends Component {
+
+ // =attributes
+ currentYear = new Date().getFullYear();
+
+}
diff --git a/addons/rose/addon/components/rose/footer/index.hbs b/addons/rose/addon/components/rose/footer/index.hbs
new file mode 100644
index 000000000..cafad5904
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/index.hbs
@@ -0,0 +1,11 @@
+
diff --git a/addons/rose/addon/components/rose/footer/index.stories.mdx b/addons/rose/addon/components/rose/footer/index.stories.mdx
new file mode 100644
index 000000000..779f1d2e6
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/index.stories.mdx
@@ -0,0 +1,42 @@
+import { Meta, Story, Preview } from '@storybook/addon-docs/blocks';
+import { hbs } from 'ember-cli-htmlbars';
+import { action } from '@storybook/addon-actions';
+import { text } from '@storybook/addon-knobs';
+
+
+
+# Footer
+
+A footer component that allows four distinct sections to be configured: brand, nav, product, and copyright.
+
+```html
+
+
+
+
+
+ Section
+ Section
+
+
+```
+
+
+ {{
+ template: hbs`
+
+
+
+
+
+ Section
+ Section
+
+
+ `,
+ context: {
+ brandName: text('brandName', 'Brand Name'),
+ copyright: text('copyright', 'Company Name'),
+ },
+ }}
+
diff --git a/addons/rose/addon/components/rose/footer/nav/external-link/index.hbs b/addons/rose/addon/components/rose/footer/nav/external-link/index.hbs
new file mode 100644
index 000000000..213ecce7a
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/nav/external-link/index.hbs
@@ -0,0 +1,7 @@
+
diff --git a/addons/rose/addon/components/rose/footer/nav/index.hbs b/addons/rose/addon/components/rose/footer/nav/index.hbs
new file mode 100644
index 000000000..444202f6e
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/nav/index.hbs
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/addons/rose/addon/components/rose/footer/product/index.hbs b/addons/rose/addon/components/rose/footer/product/index.hbs
new file mode 100644
index 000000000..6d3436db1
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/product/index.hbs
@@ -0,0 +1,11 @@
+
\ No newline at end of file
diff --git a/addons/rose/addon/styles/rose/components/_index.scss b/addons/rose/addon/styles/rose/components/_index.scss
index 19a9d3de6..6e6ef8490 100644
--- a/addons/rose/addon/styles/rose/components/_index.scss
+++ b/addons/rose/addon/styles/rose/components/_index.scss
@@ -2,6 +2,7 @@
@import 'dropdown';
@import 'form';
@import 'header';
+@import 'footer';
@import 'layout';
@import 'icon';
@import 'list';
diff --git a/addons/rose/addon/styles/rose/components/footer/_brand.scss b/addons/rose/addon/styles/rose/components/footer/_brand.scss
new file mode 100644
index 000000000..26e5f2983
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_brand.scss
@@ -0,0 +1,14 @@
+@use '../../variables/sizing';
+
+.rose-footer-brand {
+ display: flex;
+ align-items: center;
+ color: var(--ui-gray-starker-1);
+ margin: sizing.rems(xs);
+
+ svg {
+ $logoSize: sizing.rems(m);
+ display: inline-block;
+ width: $logoSize;
+ }
+}
diff --git a/addons/rose/addon/styles/rose/components/footer/_copyright.scss b/addons/rose/addon/styles/rose/components/footer/_copyright.scss
new file mode 100644
index 000000000..9db1a4fa1
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_copyright.scss
@@ -0,0 +1,14 @@
+@use '../../variables/sizing';
+
+.rose-footer-copyright {
+ display: inline-flex;
+ align-items: center;
+
+ .rose-footer-copyright-symbol {
+ margin-right: sizing.rems(xxxs);
+ }
+
+ .rose-footer-copyright-year {
+ margin-right: sizing.rems(xxs);
+ }
+}
diff --git a/addons/rose/addon/styles/rose/components/footer/_external-link.scss b/addons/rose/addon/styles/rose/components/footer/_external-link.scss
new file mode 100644
index 000000000..287db2b9b
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_external-link.scss
@@ -0,0 +1,9 @@
+@use '../../variables/sizing';
+
+.rose-footer-nav-external-link {
+ display: inline-flex;
+ align-items: center;
+ margin-right: sizing.rems(s);
+ text-decoration: underline;
+ color: var(--ui-gray-starker-1);
+}
diff --git a/addons/rose/addon/styles/rose/components/footer/_index.scss b/addons/rose/addon/styles/rose/components/footer/_index.scss
new file mode 100644
index 000000000..93e03b5ec
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_index.scss
@@ -0,0 +1,18 @@
+@use '../../variables/sizing';
+@use '../../variables/media';
+@use '../../utilities/type';
+
+@import 'brand';
+@import 'nav';
+@import 'product';
+@import 'copyright';
+@import 'external-link';
+
+.rose-footer {
+ @include type.type(xs);
+
+ display: flex;
+ justify-content: center;
+ color: var(--ui-gray-starker-1);
+ height: sizing.rems(xxl) + sizing.rems(xxs); //65px
+}
diff --git a/addons/rose/addon/styles/rose/components/footer/_nav.scss b/addons/rose/addon/styles/rose/components/footer/_nav.scss
new file mode 100644
index 000000000..bd23dde4a
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_nav.scss
@@ -0,0 +1,9 @@
+@use '../../variables/sizing';
+
+.rose-footer-nav {
+ grid-area: nav;
+ display: flex;
+ flex-wrap: wrap;
+ align-items: center;
+ margin-right: sizing.rems(s);
+}
diff --git a/addons/rose/addon/styles/rose/components/footer/_product.scss b/addons/rose/addon/styles/rose/components/footer/_product.scss
new file mode 100644
index 000000000..510fc1670
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_product.scss
@@ -0,0 +1,11 @@
+@use '../../variables/sizing';
+
+.rose-footer-product {
+ display: inline-flex;
+ align-items: center;
+ margin: 0 sizing.rems(l);
+
+ .rose-footer-product-version {
+ margin-left: sizing.rems(xxxs);
+ }
+}
diff --git a/addons/rose/app/components/rose/footer.js b/addons/rose/app/components/rose/footer.js
new file mode 100644
index 000000000..ccac33104
--- /dev/null
+++ b/addons/rose/app/components/rose/footer.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer';
\ No newline at end of file
diff --git a/addons/rose/app/components/rose/footer/brand.js b/addons/rose/app/components/rose/footer/brand.js
new file mode 100644
index 000000000..995d715ba
--- /dev/null
+++ b/addons/rose/app/components/rose/footer/brand.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer/brand';
\ No newline at end of file
diff --git a/addons/rose/app/components/rose/footer/copyright.js b/addons/rose/app/components/rose/footer/copyright.js
new file mode 100644
index 000000000..d46304fc7
--- /dev/null
+++ b/addons/rose/app/components/rose/footer/copyright.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer/copyright';
\ No newline at end of file
diff --git a/addons/rose/app/components/rose/footer/nav.js b/addons/rose/app/components/rose/footer/nav.js
new file mode 100644
index 000000000..3ca032af2
--- /dev/null
+++ b/addons/rose/app/components/rose/footer/nav.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer/nav';
\ No newline at end of file
diff --git a/addons/rose/app/components/rose/footer/nav/external-link.js b/addons/rose/app/components/rose/footer/nav/external-link.js
new file mode 100644
index 000000000..40e8cd9f6
--- /dev/null
+++ b/addons/rose/app/components/rose/footer/nav/external-link.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer/nav/external-link';
\ No newline at end of file
diff --git a/addons/rose/app/components/rose/footer/product.js b/addons/rose/app/components/rose/footer/product.js
new file mode 100644
index 000000000..7193b5690
--- /dev/null
+++ b/addons/rose/app/components/rose/footer/product.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer/product';
\ No newline at end of file
diff --git a/addons/rose/tests/integration/components/rose/footer-test.js b/addons/rose/tests/integration/components/rose/footer-test.js
new file mode 100644
index 000000000..efb3147d7
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer-test.js
@@ -0,0 +1,51 @@
+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 | rose/footer', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ assert.expect(5);
+ await render(hbs``);
+ assert.ok(find('.rose-footer'));
+ assert.notOk(find('.rose-footer-nav'));
+ assert.notOk(find('.rose-footer-brand'));
+ assert.notOk(find('.rose-footer-product'));
+ assert.notOk(find('.rose-footer-copyright'));
+ });
+
+ test('it renders with brand', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+
+ `);
+ assert.ok(find('.rose-footer-brand'));
+ });
+
+ test('it renders with nav', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+
+ `);
+ assert.ok(find('.rose-footer-nav'));
+ });
+
+ test('it renders with product', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+
+ `);
+ assert.ok(find('.rose-footer-product'));
+ });
+
+ test('it renders with copyright', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+
+ `);
+ assert.ok(find('.rose-footer-copyright'));
+ });
+
+});
diff --git a/addons/rose/tests/integration/components/rose/footer/brand-test.js b/addons/rose/tests/integration/components/rose/footer/brand-test.js
new file mode 100644
index 000000000..2910d4a56
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/brand-test.js
@@ -0,0 +1,15 @@
+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 | rose/footer/brand', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ assert.expect(2);
+ await render(hbs``);
+ assert.ok(find('.rose-footer-brand'));
+ assert.ok(find('.rose-footer-brand svg'));
+ });
+});
diff --git a/addons/rose/tests/integration/components/rose/footer/copyright-test.js b/addons/rose/tests/integration/components/rose/footer/copyright-test.js
new file mode 100644
index 000000000..63d5feed0
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/copyright-test.js
@@ -0,0 +1,20 @@
+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 | rose/footer/copyright', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ assert.expect(1);
+ await render(hbs``);
+ assert.equal(find('.rose-footer-copyright-text').textContent.trim(), 'copyright');
+ });
+
+ test('it renders with current year', async function (assert) {
+ assert.expect(1);
+ await render(hbs``);
+ assert.equal(find('.rose-footer-copyright-year').textContent.trim(), new Date().getFullYear());
+ });
+});
diff --git a/addons/rose/tests/integration/components/rose/footer/nav-test.js b/addons/rose/tests/integration/components/rose/footer/nav-test.js
new file mode 100644
index 000000000..6ba5cdb19
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/nav-test.js
@@ -0,0 +1,24 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render, find, findAll } from '@ember/test-helpers';
+import { hbs } from 'ember-cli-htmlbars';
+
+module('Integration | Component | rose/footer/nav', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ assert.expect(1);
+ await render(hbs``);
+ assert.ok(find('.rose-footer-nav'));
+ });
+
+ test('it renders nav external link elements', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+
+
+ `);
+ assert.equal(findAll('a').length, 2);
+ });
+
+});
diff --git a/addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js b/addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js
new file mode 100644
index 000000000..58f389a2f
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js
@@ -0,0 +1,15 @@
+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 | rose/footer/nav/external-link', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders with link', async function (assert) {
+ assert.expect(2);
+ await render(hbs``);
+ assert.ok(find('a'));
+ assert.ok(find('.rose-footer-nav-external-link'));
+ });
+});
diff --git a/addons/rose/tests/integration/components/rose/footer/product-test.js b/addons/rose/tests/integration/components/rose/footer/product-test.js
new file mode 100644
index 000000000..2cdd8927d
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/product-test.js
@@ -0,0 +1,22 @@
+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 | rose/footer/product', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders with product', async function (assert) {
+ assert.expect(3);
+ await render(hbs``);
+ assert.ok(find('.rose-footer-product'));
+ assert.equal(find('.rose-footer-product-text').textContent.trim(), 'boundary');
+ assert.notOk(find('.rose-footer-product-version'));
+ });
+
+ test('it renders with product and version', async function (assert) {
+ assert.expect(1);
+ await render(hbs``);
+ assert.equal(find('.rose-footer-product-version').textContent.trim(), 'v1.0');
+ });
+});
diff --git a/ui/core/app/templates/application.hbs b/ui/core/app/templates/application.hbs
index b38e02f4d..d0728605a 100644
--- a/ui/core/app/templates/application.hbs
+++ b/ui/core/app/templates/application.hbs
@@ -37,6 +37,17 @@
{{outlet}}
+
+
+
+
+
+
+ {{t "hashicorp.documentation.title"}}
+
+
+
+
diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml
index a86a36263..cdb5cb5b7 100644
--- a/ui/core/translations/en-us.yaml
+++ b/ui/core/translations/en-us.yaml
@@ -17,4 +17,11 @@ titles:
global: Global
actions: Actions
descriptions:
- empty-set: There are no items to display yet. You may be able to add items or try back later.
\ No newline at end of file
+ empty-set: There are no items to display yet. You may be able to add items or try back later.
+hashicorp:
+ title: HashiCorp
+ documentation:
+ title: Documentation
+ link: https://boundaryproject.io
+boundary:
+ version: '0.1'
\ No newline at end of file
From ce2fb39f596e8469047fde67dff3a9821c50add0 Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 22:15:30 -0400
Subject: [PATCH 10/13] refactor: Show acknowledgement text when copied using
copyabl
---
ui/core/app/components/copyable/index.hbs | 4 ++--
ui/core/app/components/copyable/index.js | 8 ++++----
.../scopes/scope/auth-methods/auth-method/-header.hbs | 6 +++++-
.../auth-methods/auth-method/accounts/account/-header.hbs | 6 +++++-
.../auth-method/accounts/account/set-password/-header.hbs | 6 +++++-
.../scope/auth-methods/auth-method/accounts/index.hbs | 6 +++++-
ui/core/app/templates/scopes/scope/auth-methods/index.hbs | 6 +++++-
.../app/templates/scopes/scope/groups/group/-header.hbs | 6 +++++-
.../app/templates/scopes/scope/groups/group/members.hbs | 6 +++++-
ui/core/app/templates/scopes/scope/groups/index.hbs | 6 +++++-
.../project/host-catalogs/host-catalog/-header.hbs | 6 +++++-
.../host-catalogs/host-catalog/host-sets/-header.hbs | 6 +++++-
.../host-catalog/host-sets/host-set/hosts.hbs | 6 +++++-
.../host-catalogs/host-catalog/host-sets/index.hbs | 6 +++++-
.../project/host-catalogs/host-catalog/hosts/-header.hbs | 6 +++++-
.../project/host-catalogs/host-catalog/hosts/index.hbs | 6 +++++-
.../scopes/scope/projects/project/host-catalogs/index.hbs | 6 +++++-
.../scopes/scope/projects/project/sessions/index.hbs | 6 +++++-
.../scopes/scope/projects/project/targets/index.hbs | 6 +++++-
.../scope/projects/project/targets/target/-header.hbs | 6 +++++-
.../scope/projects/project/targets/target/host-sets.hbs | 6 +++++-
ui/core/app/templates/scopes/scope/roles/index.hbs | 6 +++++-
ui/core/app/templates/scopes/scope/roles/role/-header.hbs | 6 +++++-
.../templates/scopes/scope/roles/role/grants/-header.hbs | 6 +++++-
.../app/templates/scopes/scope/roles/role/principals.hbs | 6 +++++-
.../scopes/scope/roles/role/principals/-header.hbs | 8 ++++++--
ui/core/app/templates/scopes/scope/users/index.hbs | 6 +++++-
ui/core/app/templates/scopes/scope/users/user/index.hbs | 6 +++++-
ui/core/tests/integration/components/copyable-test.js | 2 +-
29 files changed, 138 insertions(+), 34 deletions(-)
diff --git a/ui/core/app/components/copyable/index.hbs b/ui/core/app/components/copyable/index.hbs
index fc47d613c..499c4fc43 100644
--- a/ui/core/app/components/copyable/index.hbs
+++ b/ui/core/app/components/copyable/index.hbs
@@ -15,8 +15,8 @@
class="copyable-button"
@style="ghost"
@iconOnly={{this.icon}}
- title={{@buttonText}}
- >{{@buttonText}}
+ title={{this.copyableButtonText}}
+ >{{this.copyableButtonText}}
{{else}}
{{yield}}
diff --git a/ui/core/app/components/copyable/index.js b/ui/core/app/components/copyable/index.js
index cefc032fa..010c12758 100644
--- a/ui/core/app/components/copyable/index.js
+++ b/ui/core/app/components/copyable/index.js
@@ -1,7 +1,6 @@
import Component from '@glimmer/component';
import ClipboardJS from 'clipboard';
import { action } from '@ember/object';
-import { tracked } from '@glimmer/tracking';
import { generateComponentID } from 'rose/utilities/component-auto-id';
import { task, timeout } from 'ember-concurrency';
import { set } from '@ember/object';
@@ -12,10 +11,9 @@ export default class CopyableComponent extends Component {
// =attributes
id = generateComponentID();
- copyableButtonId = `copyable-button-${this.id}`;
icon = 'copy-action';
-
- @tracked text;
+ copyableButtonId = `copyable-button-${this.id}`;
+ copyableButtonText = this.args.buttonText;
/**
* A Ember Concurrency-based task that updates copy icon to a success state
@@ -29,8 +27,10 @@ export default class CopyableComponent extends Component {
*/
@task(function * () {
set(this, 'icon', 'copy-success');
+ set(this, 'copyableButtonText', this.args.acknowledgeText);
yield timeout(1000);
set(this, 'icon', 'copy-action');
+ set(this, 'copyableButtonText', this.args.buttonText);
}).drop() successIconTimer;
// =methods
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs
index 0748ed7b8..bd1bc825e 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.auth-method.title"}}
{{t "resources.auth-method.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs
index c7a1ec474..d67dca8b1 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/-header.hbs
@@ -1,4 +1,8 @@
{{t "resources.account.title"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs
index 1805683a2..c7d1d4670 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/account/set-password/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.account.title"}}
{{t 'resources.account.messages.set-password.description'}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
index d399eb1d8..195e5a00b 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs
@@ -24,7 +24,11 @@
{{account.username}}
-
+
{{account.id}}
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 26027d51b..08b4606fe 100644
--- a/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
+++ b/ui/core/app/templates/scopes/scope/auth-methods/index.hbs
@@ -46,7 +46,11 @@
-
+
{{authMethod.id}}
diff --git a/ui/core/app/templates/scopes/scope/groups/group/-header.hbs b/ui/core/app/templates/scopes/scope/groups/group/-header.hbs
index a876cafac..ae241529b 100644
--- a/ui/core/app/templates/scopes/scope/groups/group/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/group/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.group.title"}}
{{t "resources.group.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/groups/group/members.hbs b/ui/core/app/templates/scopes/scope/groups/group/members.hbs
index ce5eee601..a478d6b83 100644
--- a/ui/core/app/templates/scopes/scope/groups/group/members.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/group/members.hbs
@@ -17,7 +17,11 @@
{{member.displayName}}
-
+
{{member.id}}
diff --git a/ui/core/app/templates/scopes/scope/groups/index.hbs b/ui/core/app/templates/scopes/scope/groups/index.hbs
index 9f9ad3fd2..559fb8314 100644
--- a/ui/core/app/templates/scopes/scope/groups/index.hbs
+++ b/ui/core/app/templates/scopes/scope/groups/index.hbs
@@ -39,7 +39,11 @@
{{group.description}}
-
+
{{group.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs
index 8857383a2..647741ad9 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.host-catalog.title"}}
{{t "resources.host-catalog.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs
index 26afcea96..3c76eafd3 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.host-set.title"}}
{{t "resources.host-set.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs
index 7b65efa26..74cbbe2bb 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/host-set/hosts.hbs
@@ -25,7 +25,11 @@
{{host.type}}
-
+
{{host.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs
index f2dff570d..bb5f4c14c 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/host-sets/index.hbs
@@ -26,7 +26,11 @@
-
+
{{hostSet.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs
index f0d679039..d2628a102 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.host.title"}}
{{t "resources.host.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs
index 87ae8db1a..e29e8dca1 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/host-catalog/hosts/index.hbs
@@ -27,7 +27,11 @@
-
+
{{host.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs
index 2f758b992..0a70b3ee4 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/host-catalogs/index.hbs
@@ -47,7 +47,11 @@
-
+
{{hostCatalog.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs
index b4e5d3e4f..16fc16a1c 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/sessions/index.hbs
@@ -28,7 +28,11 @@
{{#each @model as |sessionAggregate|}}
-
+
{{sessionAggregate.session.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs b/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs
index ff84ac48e..2cb938f29 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/targets/index.hbs
@@ -51,7 +51,11 @@
{{/if}}
-
+
{{target.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs b/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs
index b96093e47..b6f507ea4 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/targets/target/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.target.title"}}
{{t "resources.target.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs b/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs
index e03aa2610..f6e32b99a 100644
--- a/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs
+++ b/ui/core/app/templates/scopes/scope/projects/project/targets/target/host-sets.hbs
@@ -22,7 +22,11 @@
{{t (concat 'resources.host-set.types.' hostSet.model.type)}}
-
+
{{hostSet.model.id}}
diff --git a/ui/core/app/templates/scopes/scope/roles/index.hbs b/ui/core/app/templates/scopes/scope/roles/index.hbs
index 417860216..77c5d7d6a 100644
--- a/ui/core/app/templates/scopes/scope/roles/index.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/index.hbs
@@ -41,7 +41,11 @@
{{role.description}}
-
+
{{role.id}}
diff --git a/ui/core/app/templates/scopes/scope/roles/role/-header.hbs b/ui/core/app/templates/scopes/scope/roles/role/-header.hbs
index 926771735..03164c9b2 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.role.title"}}
{{t "resources.role.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs b/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs
index ccea2b2d0..48e974188 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/grants/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.role.title"}}
{{t "resources.role.grant.description"}}
-
+
{{@model.id}}
\ No newline at end of file
diff --git a/ui/core/app/templates/scopes/scope/roles/role/principals.hbs b/ui/core/app/templates/scopes/scope/roles/role/principals.hbs
index 58041d4a0..668b93e4f 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/principals.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/principals.hbs
@@ -21,7 +21,11 @@
{{t (concat 'resources.role.principal.types.' principal.type)}}
-
+
{{principal.model.id}}
diff --git a/ui/core/app/templates/scopes/scope/roles/role/principals/-header.hbs b/ui/core/app/templates/scopes/scope/roles/role/principals/-header.hbs
index 057a23f76..499d7ff96 100644
--- a/ui/core/app/templates/scopes/scope/roles/role/principals/-header.hbs
+++ b/ui/core/app/templates/scopes/scope/roles/role/principals/-header.hbs
@@ -1,5 +1,9 @@
{{t "resources.role.title"}}
{{t "resources.role.principal.description"}}
-
- {{@model.role.id}}
+
+ {{@model.id}}
diff --git a/ui/core/app/templates/scopes/scope/users/index.hbs b/ui/core/app/templates/scopes/scope/users/index.hbs
index 50bcd7b74..7f5154949 100644
--- a/ui/core/app/templates/scopes/scope/users/index.hbs
+++ b/ui/core/app/templates/scopes/scope/users/index.hbs
@@ -41,7 +41,11 @@
{{user.description}}
-
+
{{user.id}}
diff --git a/ui/core/app/templates/scopes/scope/users/user/index.hbs b/ui/core/app/templates/scopes/scope/users/user/index.hbs
index 7f9218f1b..e88672ab6 100644
--- a/ui/core/app/templates/scopes/scope/users/user/index.hbs
+++ b/ui/core/app/templates/scopes/scope/users/user/index.hbs
@@ -7,7 +7,11 @@
{{t "resources.user.title"}}
{{t "resources.user.description"}}
-
+
{{@model.id}}
diff --git a/ui/core/tests/integration/components/copyable-test.js b/ui/core/tests/integration/components/copyable-test.js
index 07be2788f..8d6a29cf9 100644
--- a/ui/core/tests/integration/components/copyable-test.js
+++ b/ui/core/tests/integration/components/copyable-test.js
@@ -7,7 +7,7 @@ module('Integration | Component | copyable', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function(assert) {
- await render(hbs`text`);
+ await render(hbs`text`);
assert.ok(find('.copyable'));
assert.equal(find('.copyable-content').textContent.trim(), 'text');
assert.equal(find('.copyable-button').textContent.trim(), 'Copy me');
From b19cbee609730ebdcf884c77c9675a75f6a6973a Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 22:25:40 -0400
Subject: [PATCH 11/13] feat: Disable change password link in header
---
ui/core/app/router.js | 3 ++-
ui/core/app/templates/application.hbs | 4 ++--
ui/core/tests/acceptance/accounts/change-password-test.js | 5 +++++
ui/core/tests/unit/routes/account/change-password-test.js | 5 +++--
4 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/ui/core/app/router.js b/ui/core/app/router.js
index 0894289f9..bebf3f0a2 100644
--- a/ui/core/app/router.js
+++ b/ui/core/app/router.js
@@ -94,6 +94,7 @@ Router.map(function () {
});
this.route('account', function() {
- this.route('change-password');
+ // Enable after full account feature implementation
+ // this.route('change-password');
});
});
diff --git a/ui/core/app/templates/application.hbs b/ui/core/app/templates/application.hbs
index f8de5b3f9..d63eee931 100644
--- a/ui/core/app/templates/application.hbs
+++ b/ui/core/app/templates/application.hbs
@@ -19,9 +19,9 @@
@iconOnly={{true}}
@icon="boundary-icons/user-profile" as |dropdown|
>
-
+ {{!--
{{t 'actions.change-password'}}
-
+ --}}
diff --git a/ui/core/tests/acceptance/accounts/change-password-test.js b/ui/core/tests/acceptance/accounts/change-password-test.js
index 27a28ba3d..fee06b101 100644
--- a/ui/core/tests/acceptance/accounts/change-password-test.js
+++ b/ui/core/tests/acceptance/accounts/change-password-test.js
@@ -1,3 +1,5 @@
+// Enable after account workflow implementation
+/*
import { module, test } from 'qunit';
import { visit, currentURL, click, find, fillIn } from '@ember/test-helpers';
import { setupApplicationTest } from 'ember-qunit';
@@ -15,6 +17,7 @@ module('Acceptance | accounts | change password', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
+
const instances = {
scopes: {
global: null,
@@ -114,4 +117,6 @@ module('Acceptance | accounts | change password', function (hooks) {
await visit(urls.changePassword);
assert.notEqual(currentURL(), urls.changePassword);
});
+
});
+*/
diff --git a/ui/core/tests/unit/routes/account/change-password-test.js b/ui/core/tests/unit/routes/account/change-password-test.js
index ee6856d35..4481d783e 100644
--- a/ui/core/tests/unit/routes/account/change-password-test.js
+++ b/ui/core/tests/unit/routes/account/change-password-test.js
@@ -5,7 +5,8 @@ module('Unit | Route | account/change-password', function(hooks) {
setupTest(hooks);
test('it exists', function(assert) {
- let route = this.owner.lookup('route:account/change-password');
- assert.ok(route);
+ // let route = this.owner.lookup('route:account/change-password');
+ // assert.ok(route);
+ assert.expect(0);
});
});
From d26f6896bcc55a29a16d20cbc11b700446162f88 Mon Sep 17 00:00:00 2001
From: Susmitha Girumala
Date: Wed, 30 Sep 2020 23:03:01 -0400
Subject: [PATCH 12/13] refactor: Simplify rose/footer component
Reduce number of elements footer supports
---
.../addon/components/rose/footer/index.hbs | 5 ++--
.../components/rose/footer/index.stories.mdx | 18 +++++++-------
.../rose/footer/nav/external-link/index.hbs | 7 ------
.../components/rose/footer/nav/index.hbs | 2 +-
.../components/rose/footer/nav/link/index.hbs | 20 ++++++++++++++++
.../rose/components/footer/_copyright.scss | 14 -----------
.../styles/rose/components/footer/_index.scss | 5 ++--
.../{_external-link.scss => _link.scss} | 4 ++--
.../rose/components/footer/_product.scss | 11 ---------
.../styles/rose/components/footer/_text.scss | 7 ++++++
.../rose/footer/nav/external-link.js | 1 -
.../app/components/rose/footer/nav/link.js | 1 +
.../components/rose/footer-test.js | 19 ++++-----------
.../components/rose/footer/brand-test.js | 15 ------------
.../components/rose/footer/copyright-test.js | 20 ----------------
.../components/rose/footer/nav-test.js | 4 ++--
.../rose/footer/nav/external-link-test.js | 15 ------------
.../components/rose/footer/nav/link-test.js | 22 +++++++++++++++++
.../components/rose/footer/product-test.js | 22 -----------------
.../components/rose/footer/text-test.js | 24 +++++++++++++++++++
ui/core/app/templates/application.hbs | 6 ++---
ui/core/translations/en-us.yaml | 4 ++--
22 files changed, 101 insertions(+), 145 deletions(-)
delete mode 100644 addons/rose/addon/components/rose/footer/nav/external-link/index.hbs
create mode 100644 addons/rose/addon/components/rose/footer/nav/link/index.hbs
delete mode 100644 addons/rose/addon/styles/rose/components/footer/_copyright.scss
rename addons/rose/addon/styles/rose/components/footer/{_external-link.scss => _link.scss} (69%)
delete mode 100644 addons/rose/addon/styles/rose/components/footer/_product.scss
create mode 100644 addons/rose/addon/styles/rose/components/footer/_text.scss
delete mode 100644 addons/rose/app/components/rose/footer/nav/external-link.js
create mode 100644 addons/rose/app/components/rose/footer/nav/link.js
delete mode 100644 addons/rose/tests/integration/components/rose/footer/brand-test.js
delete mode 100644 addons/rose/tests/integration/components/rose/footer/copyright-test.js
delete mode 100644 addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/nav/link-test.js
delete mode 100644 addons/rose/tests/integration/components/rose/footer/product-test.js
create mode 100644 addons/rose/tests/integration/components/rose/footer/text-test.js
diff --git a/addons/rose/addon/components/rose/footer/index.hbs b/addons/rose/addon/components/rose/footer/index.hbs
index cafad5904..bbe5ecc72 100644
--- a/addons/rose/addon/components/rose/footer/index.hbs
+++ b/addons/rose/addon/components/rose/footer/index.hbs
@@ -3,9 +3,8 @@
class="rose-footer"
>
{{yield (hash
- brand=(component 'rose/footer/brand')
- copyright=(component 'rose/footer/copyright')
- product=(component 'rose/footer/product')
nav=(component 'rose/footer/nav')
+ brand=(component 'rose/footer/brand')
+ text=(component "rose/anonymous" class="rose-footer-text")
)}}
diff --git a/addons/rose/addon/components/rose/footer/index.stories.mdx b/addons/rose/addon/components/rose/footer/index.stories.mdx
index 779f1d2e6..608bc1068 100644
--- a/addons/rose/addon/components/rose/footer/index.stories.mdx
+++ b/addons/rose/addon/components/rose/footer/index.stories.mdx
@@ -7,16 +7,15 @@ import { text } from '@storybook/addon-knobs';
# Footer
-A footer component that allows four distinct sections to be configured: brand, nav, product, and copyright.
+A footer component that allows four distinct sections to be configured: brand, nav, and text.
```html
-
-
+ Text
- Section
- Section
+ Section
+ Section
```
@@ -26,17 +25,16 @@ A footer component that allows four distinct sections to be configured: brand, n
template: hbs`
-
-
+ {{footerText}}
- Section
- Section
+ Section
+ Section
`,
context: {
brandName: text('brandName', 'Brand Name'),
- copyright: text('copyright', 'Company Name'),
+ footerText: text('footerText', 'Text'),
},
}}
diff --git a/addons/rose/addon/components/rose/footer/nav/external-link/index.hbs b/addons/rose/addon/components/rose/footer/nav/external-link/index.hbs
deleted file mode 100644
index 213ecce7a..000000000
--- a/addons/rose/addon/components/rose/footer/nav/external-link/index.hbs
+++ /dev/null
@@ -1,7 +0,0 @@
-
diff --git a/addons/rose/addon/components/rose/footer/nav/index.hbs b/addons/rose/addon/components/rose/footer/nav/index.hbs
index 444202f6e..c03ac88c9 100644
--- a/addons/rose/addon/components/rose/footer/nav/index.hbs
+++ b/addons/rose/addon/components/rose/footer/nav/index.hbs
@@ -1,5 +1,5 @@
\ No newline at end of file
diff --git a/addons/rose/addon/components/rose/footer/nav/link/index.hbs b/addons/rose/addon/components/rose/footer/nav/link/index.hbs
new file mode 100644
index 000000000..bebaacc29
--- /dev/null
+++ b/addons/rose/addon/components/rose/footer/nav/link/index.hbs
@@ -0,0 +1,20 @@
+{{#if @href}}
+
+{{/if}}
+
+{{#if @route}}
+
+{{/if}}
diff --git a/addons/rose/addon/styles/rose/components/footer/_copyright.scss b/addons/rose/addon/styles/rose/components/footer/_copyright.scss
deleted file mode 100644
index 9db1a4fa1..000000000
--- a/addons/rose/addon/styles/rose/components/footer/_copyright.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-@use '../../variables/sizing';
-
-.rose-footer-copyright {
- display: inline-flex;
- align-items: center;
-
- .rose-footer-copyright-symbol {
- margin-right: sizing.rems(xxxs);
- }
-
- .rose-footer-copyright-year {
- margin-right: sizing.rems(xxs);
- }
-}
diff --git a/addons/rose/addon/styles/rose/components/footer/_index.scss b/addons/rose/addon/styles/rose/components/footer/_index.scss
index 93e03b5ec..9de207b95 100644
--- a/addons/rose/addon/styles/rose/components/footer/_index.scss
+++ b/addons/rose/addon/styles/rose/components/footer/_index.scss
@@ -4,9 +4,8 @@
@import 'brand';
@import 'nav';
-@import 'product';
-@import 'copyright';
-@import 'external-link';
+@import 'text';
+@import 'link';
.rose-footer {
@include type.type(xs);
diff --git a/addons/rose/addon/styles/rose/components/footer/_external-link.scss b/addons/rose/addon/styles/rose/components/footer/_link.scss
similarity index 69%
rename from addons/rose/addon/styles/rose/components/footer/_external-link.scss
rename to addons/rose/addon/styles/rose/components/footer/_link.scss
index 287db2b9b..dc35db4c0 100644
--- a/addons/rose/addon/styles/rose/components/footer/_external-link.scss
+++ b/addons/rose/addon/styles/rose/components/footer/_link.scss
@@ -1,9 +1,9 @@
@use '../../variables/sizing';
-.rose-footer-nav-external-link {
+.rose-footer-nav-link {
display: inline-flex;
align-items: center;
- margin-right: sizing.rems(s);
text-decoration: underline;
color: var(--ui-gray-starker-1);
+ margin: 0 sizing.rems(xs);
}
diff --git a/addons/rose/addon/styles/rose/components/footer/_product.scss b/addons/rose/addon/styles/rose/components/footer/_product.scss
deleted file mode 100644
index 510fc1670..000000000
--- a/addons/rose/addon/styles/rose/components/footer/_product.scss
+++ /dev/null
@@ -1,11 +0,0 @@
-@use '../../variables/sizing';
-
-.rose-footer-product {
- display: inline-flex;
- align-items: center;
- margin: 0 sizing.rems(l);
-
- .rose-footer-product-version {
- margin-left: sizing.rems(xxxs);
- }
-}
diff --git a/addons/rose/addon/styles/rose/components/footer/_text.scss b/addons/rose/addon/styles/rose/components/footer/_text.scss
new file mode 100644
index 000000000..9e7b29b8b
--- /dev/null
+++ b/addons/rose/addon/styles/rose/components/footer/_text.scss
@@ -0,0 +1,7 @@
+@use '../../variables/sizing';
+
+.rose-footer-text {
+ display: inline-flex;
+ align-items: center;
+ margin: 0 sizing.rems(xs);
+}
diff --git a/addons/rose/app/components/rose/footer/nav/external-link.js b/addons/rose/app/components/rose/footer/nav/external-link.js
deleted file mode 100644
index 40e8cd9f6..000000000
--- a/addons/rose/app/components/rose/footer/nav/external-link.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from 'rose/components/rose/footer/nav/external-link';
\ No newline at end of file
diff --git a/addons/rose/app/components/rose/footer/nav/link.js b/addons/rose/app/components/rose/footer/nav/link.js
new file mode 100644
index 000000000..e38b27530
--- /dev/null
+++ b/addons/rose/app/components/rose/footer/nav/link.js
@@ -0,0 +1 @@
+export { default } from 'rose/components/rose/footer/nav/link';
\ No newline at end of file
diff --git a/addons/rose/tests/integration/components/rose/footer-test.js b/addons/rose/tests/integration/components/rose/footer-test.js
index efb3147d7..4a43f0d4f 100644
--- a/addons/rose/tests/integration/components/rose/footer-test.js
+++ b/addons/rose/tests/integration/components/rose/footer-test.js
@@ -7,13 +7,12 @@ module('Integration | Component | rose/footer', function(hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
- assert.expect(5);
+ assert.expect(4);
await render(hbs``);
assert.ok(find('.rose-footer'));
assert.notOk(find('.rose-footer-nav'));
+ assert.notOk(find('.rose-footer-text'));
assert.notOk(find('.rose-footer-brand'));
- assert.notOk(find('.rose-footer-product'));
- assert.notOk(find('.rose-footer-copyright'));
});
test('it renders with brand', async function (assert) {
@@ -32,20 +31,12 @@ module('Integration | Component | rose/footer', function(hooks) {
assert.ok(find('.rose-footer-nav'));
});
- test('it renders with product', async function (assert) {
+ test('it renders with text', async function (assert) {
assert.expect(1);
await render(hbs`
-
+
`);
- assert.ok(find('.rose-footer-product'));
- });
-
- test('it renders with copyright', async function (assert) {
- assert.expect(1);
- await render(hbs`
-
- `);
- assert.ok(find('.rose-footer-copyright'));
+ assert.ok(find('.rose-footer-text'));
});
});
diff --git a/addons/rose/tests/integration/components/rose/footer/brand-test.js b/addons/rose/tests/integration/components/rose/footer/brand-test.js
deleted file mode 100644
index 2910d4a56..000000000
--- a/addons/rose/tests/integration/components/rose/footer/brand-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-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 | rose/footer/brand', function(hooks) {
- setupRenderingTest(hooks);
-
- test('it renders', async function (assert) {
- assert.expect(2);
- await render(hbs``);
- assert.ok(find('.rose-footer-brand'));
- assert.ok(find('.rose-footer-brand svg'));
- });
-});
diff --git a/addons/rose/tests/integration/components/rose/footer/copyright-test.js b/addons/rose/tests/integration/components/rose/footer/copyright-test.js
deleted file mode 100644
index 63d5feed0..000000000
--- a/addons/rose/tests/integration/components/rose/footer/copyright-test.js
+++ /dev/null
@@ -1,20 +0,0 @@
-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 | rose/footer/copyright', function(hooks) {
- setupRenderingTest(hooks);
-
- test('it renders', async function (assert) {
- assert.expect(1);
- await render(hbs``);
- assert.equal(find('.rose-footer-copyright-text').textContent.trim(), 'copyright');
- });
-
- test('it renders with current year', async function (assert) {
- assert.expect(1);
- await render(hbs``);
- assert.equal(find('.rose-footer-copyright-year').textContent.trim(), new Date().getFullYear());
- });
-});
diff --git a/addons/rose/tests/integration/components/rose/footer/nav-test.js b/addons/rose/tests/integration/components/rose/footer/nav-test.js
index 6ba5cdb19..782602f44 100644
--- a/addons/rose/tests/integration/components/rose/footer/nav-test.js
+++ b/addons/rose/tests/integration/components/rose/footer/nav-test.js
@@ -15,8 +15,8 @@ module('Integration | Component | rose/footer/nav', function(hooks) {
test('it renders nav external link elements', async function (assert) {
assert.expect(1);
await render(hbs`
-
-
+
+
`);
assert.equal(findAll('a').length, 2);
});
diff --git a/addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js b/addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js
deleted file mode 100644
index 58f389a2f..000000000
--- a/addons/rose/tests/integration/components/rose/footer/nav/external-link-test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-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 | rose/footer/nav/external-link', function(hooks) {
- setupRenderingTest(hooks);
-
- test('it renders with link', async function (assert) {
- assert.expect(2);
- await render(hbs``);
- assert.ok(find('a'));
- assert.ok(find('.rose-footer-nav-external-link'));
- });
-});
diff --git a/addons/rose/tests/integration/components/rose/footer/nav/link-test.js b/addons/rose/tests/integration/components/rose/footer/nav/link-test.js
new file mode 100644
index 000000000..d5405db01
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/nav/link-test.js
@@ -0,0 +1,22 @@
+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 | rose/footer/nav/link', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders with @href', async function (assert) {
+ assert.expect(2);
+ await render(hbs``);
+ assert.ok(find('a'));
+ assert.ok(find('.rose-footer-nav-link'));
+ });
+
+ test('it renders with @route', async function (assert) {
+ assert.expect(2);
+ await render(hbs``);
+ assert.ok(find('a'));
+ assert.ok(find('.rose-footer-nav-link'));
+ });
+});
diff --git a/addons/rose/tests/integration/components/rose/footer/product-test.js b/addons/rose/tests/integration/components/rose/footer/product-test.js
deleted file mode 100644
index 2cdd8927d..000000000
--- a/addons/rose/tests/integration/components/rose/footer/product-test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-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 | rose/footer/product', function(hooks) {
- setupRenderingTest(hooks);
-
- test('it renders with product', async function (assert) {
- assert.expect(3);
- await render(hbs``);
- assert.ok(find('.rose-footer-product'));
- assert.equal(find('.rose-footer-product-text').textContent.trim(), 'boundary');
- assert.notOk(find('.rose-footer-product-version'));
- });
-
- test('it renders with product and version', async function (assert) {
- assert.expect(1);
- await render(hbs``);
- assert.equal(find('.rose-footer-product-version').textContent.trim(), 'v1.0');
- });
-});
diff --git a/addons/rose/tests/integration/components/rose/footer/text-test.js b/addons/rose/tests/integration/components/rose/footer/text-test.js
new file mode 100644
index 000000000..d3cbfacff
--- /dev/null
+++ b/addons/rose/tests/integration/components/rose/footer/text-test.js
@@ -0,0 +1,24 @@
+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 | rose/footer/text', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('it renders', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+
+ `);
+ assert.ok(find('.rose-footer-text'));
+ });
+
+ test('it renders content', async function (assert) {
+ assert.expect(1);
+ await render(hbs`
+ content
+ `);
+ assert.equal(find('.rose-footer-text').textContent.trim(), 'content');
+ });
+});
diff --git a/ui/core/app/templates/application.hbs b/ui/core/app/templates/application.hbs
index 5a8003366..7d2f00db3 100644
--- a/ui/core/app/templates/application.hbs
+++ b/ui/core/app/templates/application.hbs
@@ -40,10 +40,10 @@
-
-
+ {{t "hashicorp.copyright"}}
+ {{t "hashicorp.product"}}
- {{t "hashicorp.documentation.title"}}
+ {{t "hashicorp.documentation.title"}}
diff --git a/ui/core/translations/en-us.yaml b/ui/core/translations/en-us.yaml
index cdb5cb5b7..6755b8976 100644
--- a/ui/core/translations/en-us.yaml
+++ b/ui/core/translations/en-us.yaml
@@ -20,8 +20,8 @@ descriptions:
empty-set: There are no items to display yet. You may be able to add items or try back later.
hashicorp:
title: HashiCorp
+ copyright: © 2020 HashiCorp
+ product: Boundary v0.1
documentation:
title: Documentation
link: https://boundaryproject.io
-boundary:
- version: '0.1'
\ No newline at end of file
From d76bc046a66d6d87ee5db8fa401bcd95484d226b Mon Sep 17 00:00:00 2001
From: Randall Morey
Date: Thu, 1 Oct 2020 11:19:41 -0400
Subject: [PATCH 13/13] chore: remove comment
---
addons/rose/addon/styles/rose/components/footer/_index.scss | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/addons/rose/addon/styles/rose/components/footer/_index.scss b/addons/rose/addon/styles/rose/components/footer/_index.scss
index 9de207b95..9632c4e0c 100644
--- a/addons/rose/addon/styles/rose/components/footer/_index.scss
+++ b/addons/rose/addon/styles/rose/components/footer/_index.scss
@@ -13,5 +13,5 @@
display: flex;
justify-content: center;
color: var(--ui-gray-starker-1);
- height: sizing.rems(xxl) + sizing.rems(xxs); //65px
+ height: sizing.rems(xxl) + sizing.rems(xxs);
}