diff --git a/addons/api/addon/models/managed-group.js b/addons/api/addon/models/managed-group.js index 426807de2..5843bb0e5 100644 --- a/addons/api/addon/models/managed-group.js +++ b/addons/api/addon/models/managed-group.js @@ -5,6 +5,14 @@ import { A } from '@ember/array'; export default class ManagedGroupModel extends GeneratedManagedGroupModel { // =attributes + + // =error attributes + // These attributes exist solely to capture errors on nested fields. + // See the application adapter's error normalization method for + // more information. + + @attr('string', { readOnly: true }) attributes_filter; + /** * Members is read-only under normal circumstances. But members can * be persisted via calls to `addMembers()` or `removeMembers()`. diff --git a/addons/api/addon/serializers/managed-group.js b/addons/api/addon/serializers/managed-group.js index cb03236af..f42fc78d2 100644 --- a/addons/api/addon/serializers/managed-group.js +++ b/addons/api/addon/serializers/managed-group.js @@ -1,3 +1,10 @@ import ApplicationSerializer from './application'; -export default class ManagedGroupSerializer extends ApplicationSerializer {} +export default class ManagedGroupSerializer extends ApplicationSerializer { + // =properties + + /** + * @type {boolean} + */ + serializeScopeID = false; +} diff --git a/addons/api/app/serializers/managed-group.js b/addons/api/app/serializers/managed-group.js new file mode 100644 index 000000000..799590738 --- /dev/null +++ b/addons/api/app/serializers/managed-group.js @@ -0,0 +1 @@ +export { default } from 'api/serializers/managed-group'; diff --git a/addons/api/mirage/config.js b/addons/api/mirage/config.js index 0bfff1ff1..f636c68ea 100644 --- a/addons/api/mirage/config.js +++ b/addons/api/mirage/config.js @@ -522,6 +522,9 @@ export default function () { return managedGroups.where({ authMethodId }); } ); + this.get('/managed-groups/:id'); + this.del('/managed-groups/:id'); + this.post('/managed-groups'); /* Uncomment the following line and the Response import above * Then change the response code to simulate error responses. diff --git a/addons/api/mirage/factories/auth-method.js b/addons/api/mirage/factories/auth-method.js index 051ea096f..865c10b3d 100644 --- a/addons/api/mirage/factories/auth-method.js +++ b/addons/api/mirage/factories/auth-method.js @@ -15,6 +15,7 @@ export default factory.extend({ authorized_collection_actions: () => { return { accounts: ['create', 'list'], + 'managed-groups': ['create', 'list'], }; }, id: (i) => `auth-method-id-${i}`, @@ -34,7 +35,9 @@ export default factory.extend({ user.update({ accountIds: [id] }); }); - server.createList('managed-group', 2, { scope, authMethod }); + if (type === 'oidc') { + server.createList('managed-group', 2, { scope, authMethod }); + } }, }), }); diff --git a/addons/api/mirage/factories/managed-group.js b/addons/api/mirage/factories/managed-group.js index c65e62334..9460f847f 100644 --- a/addons/api/mirage/factories/managed-group.js +++ b/addons/api/mirage/factories/managed-group.js @@ -1,8 +1,12 @@ import factory from '../generated/factories/managed-group'; +import { random } from 'faker'; import permissions from '../helpers/permissions'; +const types = ['oidc']; + export default factory.extend({ id: (i) => `managed-groups-id-${i}`, + type: (i) => types[i % types.length], authorized_actions: () => permissions.authorizedActionsFor('managed-group') || [ @@ -11,4 +15,13 @@ export default factory.extend({ 'update', 'delete', ], + + attributes() { + switch (this.type) { + case 'oidc': + return { + filter: random.words(), + }; + } + }, }); diff --git a/addons/api/mirage/generated/factories/managed-group.js b/addons/api/mirage/generated/factories/managed-group.js index 17bb7d6c6..a041c0f50 100644 --- a/addons/api/mirage/generated/factories/managed-group.js +++ b/addons/api/mirage/generated/factories/managed-group.js @@ -11,15 +11,4 @@ export default Factory.extend({ created_time: () => date.recent(), updated_time: () => date.recent(), version: () => datatype.number(), - type: 'oidc', - attributes: function () { - switch (this.type) { - case 'oidc': - return { - filter: random.words(), - }; - default: - return; - } - }, }); diff --git a/addons/api/mirage/scenarios/default.js b/addons/api/mirage/scenarios/default.js index 9291f8a3e..965234b5d 100644 --- a/addons/api/mirage/scenarios/default.js +++ b/addons/api/mirage/scenarios/default.js @@ -22,7 +22,7 @@ export default function (server) { // Auth const globalAuthMethods = server.createList( 'auth-method', - 1, + 4, { scope: globalScope }, 'withAccountsAndUsersAndManagedGroups' ); diff --git a/addons/api/mirage/serializers/managed-groups.js b/addons/api/mirage/serializers/managed-group.js similarity index 100% rename from addons/api/mirage/serializers/managed-groups.js rename to addons/api/mirage/serializers/managed-group.js diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml index cb7b69832..05105fbac 100644 --- a/addons/core/translations/form/en-us.yaml +++ b/addons/core/translations/form/en-us.yaml @@ -115,3 +115,6 @@ value: callback_url: label: Callback URL help: The URL to which the third-party provider sends the authentication response. Paste this into the provider configuration. +filter: + label: Filter + help: A boolean expression defining a filter run against the provided information. diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 91ed16ac1..4d7f4842f 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -351,3 +351,14 @@ scope: title_plural: Scopes messages: cannot_read: While you do not have permission to read this scope, you may have permission to view resources within it. +managed-group: + title: Managed Group + title_plural: Managed Groups + description: A managed group represents a collection of accounts. + actions: + delete: Delete Managed Group + create: Create Managed Group + messages: + welcome: + title: Welcome to Managed Groups + description: Create and manage managed groups for an auth method. diff --git a/ui/admin/app/components/form/managed-group/index.hbs b/ui/admin/app/components/form/managed-group/index.hbs new file mode 100644 index 000000000..523bb52bb --- /dev/null +++ b/ui/admin/app/components/form/managed-group/index.hbs @@ -0,0 +1,80 @@ + + + + + {{#if @model.errors.name}} + + {{#each @model.errors.name as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.description}} + + {{#each @model.errors.description as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + + + {{#if @model.errors.filter}} + + {{#each @model.errors.filter as |error|}} + {{error.message}} + {{/each}} + + {{/if}} + + {{#if (can 'save model' @model)}} + + {{/if}} + \ No newline at end of file diff --git a/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups.js b/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups.js new file mode 100644 index 000000000..8d72eb80d --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups.js @@ -0,0 +1,18 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsController extends Controller { + // =services + + @service intl; + + // =attributes + + /** + * Translated managed groups breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('resources.managed-group.title_plural'); + } +} diff --git a/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.js b/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.js new file mode 100644 index 000000000..4b770231b --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.js @@ -0,0 +1,13 @@ +import Controller from '@ember/controller'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsManagedGroupController extends Controller { + // =attributes + + /** + * A managed group breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.model.displayName; + } +} diff --git a/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups/new.js b/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups/new.js new file mode 100644 index 000000000..cf16a4e94 --- /dev/null +++ b/ui/admin/app/controllers/scopes/scope/auth-methods/auth-method/managed-groups/new.js @@ -0,0 +1,17 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsNewController extends Controller { + // =services + + @service intl; + + // =attributes + /** + * Translated new managed group breadcrumb + * @type {string} + */ + get breadCrumb() { + return this.intl.t('titles.new'); + } +} diff --git a/ui/admin/app/router.js b/ui/admin/app/router.js index 7e62a2ce4..edc70b62d 100644 --- a/ui/admin/app/router.js +++ b/ui/admin/app/router.js @@ -55,6 +55,14 @@ Router.map(function () { }); this.route('new'); }); + this.route('managed-groups', function () { + this.route( + 'managed-group', + { path: ':managed_group_id' }, + function () {} + ); + this.route('new'); + }); }); this.route('new'); }); diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups.js new file mode 100644 index 000000000..770d1357e --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups.js @@ -0,0 +1,88 @@ +import Route from '@ember/routing/route'; +import { action } from '@ember/object'; +import { inject as service } from '@ember/service'; +import loading from 'ember-loading/decorator'; +import { confirm } from 'core/decorators/confirm'; +import { notifySuccess, notifyError } from 'core/decorators/notify'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsRoute extends Route { + // =services + + @service intl; + @service notify; + @service can; + + //=methods + + /** + * + * @returns {Promise{[ManagedGroupsModel]}} + */ + model() { + const authMethod = this.modelFor('scopes.scope.auth-methods.auth-method'); + const { id: auth_method_id } = authMethod; + const canListManagedGroups = this.can.can('list collection', authMethod, { + collection: 'managed-groups', + }); + + if (canListManagedGroups) { + return this.store.query('managed-group', { auth_method_id }); + } + } + + // =actions + /** + * Rollback changes on a managed group. + * @param {ManagedGroupModel} managedGroup + */ + @action + cancel(managedGroup) { + const { isNew } = managedGroup; + managedGroup.rollbackAttributes(); + if (isNew) { + this.transitionTo('scopes.scope.auth-methods.auth-method.managed-groups'); + } + } + + /** + * Save a managed group in current scope. + * @param {ManagedGroupModel} managedGroup + */ + @action + @loading + @notifyError(({ message }) => message) + @notifySuccess(({ isNew }) => + isNew ? 'notifications.create-success' : 'notifications.save-success' + ) + async save(managedGroup) { + await managedGroup.save(); + if (this.can.can('read model', managedGroup)) { + await this.transitionTo( + 'scopes.scope.auth-methods.auth-method.managed-groups.managed-group', + managedGroup + ); + } else { + await this.transitionTo( + 'scopes.scope.auth-methods.auth-method.managed-groups' + ); + } + this.refresh(); + } + + /** + * Delete a managed group in current scope and redirect to index + * @param {ManagedGroupModel} managed group + */ + @action + @loading + @confirm('questions.delete-confirm') + @notifyError(({ message }) => message, { catch: true }) + @notifySuccess('notifications.delete-success') + async delete(managedGroup) { + await managedGroup.destroyRecord(); + await this.replaceWith( + 'scopes.scope.auth-methods.auth-method.managed-groups' + ); + this.refresh(); + } +} diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/index.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/index.js new file mode 100644 index 000000000..7cdc46a89 --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/index.js @@ -0,0 +1,9 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsIndexRoute extends Route { + setupController(controller) { + const authMethod = this.modelFor('scopes.scope.auth-methods.auth-method'); + super.setupController(...arguments); + controller.setProperties({ authMethod }); + } +} diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.js new file mode 100644 index 000000000..816b537da --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.js @@ -0,0 +1,49 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsManagedGroupRoute extends Route { + // =methods + + /** + * Load managed group by ID. + * @param {object} params + * @param {string} params.managed_group_id + * @returns {ManagedGroupModel} + */ + model({ managed_group_id }) { + return this.store.findRecord('managed-group', managed_group_id, { + reload: true, + }); + } + + /** + * Render the route-set specific page sections + * @override + */ + renderTemplate() { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-header', + { + into: 'scopes/scope/auth-methods/auth-method', + outlet: 'header', + } + ); + + this.render( + 'scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-actions', + { + into: 'scopes/scope/auth-methods/auth-method', + outlet: 'actions', + } + ); + + this.render( + 'scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-navigation', + { + into: 'scopes/scope/auth-methods/auth-method', + outlet: 'navigation', + } + ); + } +} diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index.js new file mode 100644 index 000000000..0dbea955a --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsManagedGroupIndexRoute extends Route {} diff --git a/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/new.js b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/new.js new file mode 100644 index 000000000..ca2b1473c --- /dev/null +++ b/ui/admin/app/routes/scopes/scope/auth-methods/auth-method/managed-groups/new.js @@ -0,0 +1,36 @@ +import Route from '@ember/routing/route'; + +export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsNewRoute extends Route { + // =methods + model() { + const { id: auth_method_id, type } = this.modelFor( + 'scopes.scope.auth-methods.auth-method' + ); + return this.store.createRecord('managed-group', { + type, + auth_method_id, + }); + } + + renderTemplate() { + super.renderTemplate(...arguments); + + this.render( + 'scopes/scope/auth-methods/auth-method/managed-groups/new/-header', + { + into: 'scopes/scope/auth-methods/auth-method', + outlet: 'header', + } + ); + + this.render('_empty', { + into: 'scopes/scope/auth-methods/auth-method', + outlet: 'actions', + }); + + this.render('_empty', { + into: 'scopes/scope/auth-methods/auth-method', + outlet: 'navigation', + }); + } +} diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs index a33cfdb42..5626026a6 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/-actions.hbs @@ -67,6 +67,19 @@ {{/if}} + {{#if (feature-flag 'managed-groups')}} + {{#if (can 'create collection' @model collection='managed-groups')}} + {{#if @model.isOIDC}} + + {{t 'resources.managed-group.actions.create'}} + + {{/if}} + {{/if}} + {{/if}} + {{#if (can 'delete model' @model)}} {{/if}} + + {{#if (feature-flag 'managed-groups')}} + {{#if (can 'navigate collection' @model collection='managed-groups')}} + {{#if @model.isOIDC}} + + {{t 'resources.managed-group.title_plural'}} + + {{/if}} + {{/if}} + {{/if}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs index 3f9a64787..67ba884ae 100644 --- a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/accounts/index.hbs @@ -1,5 +1,4 @@ {{#if @model}} - {{! OIDC accounts display more fields }} {{#if @model.firstObject.isOIDC}} diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups.hbs new file mode 100644 index 000000000..cfe68fbff --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups.hbs @@ -0,0 +1,3 @@ +{{page-title (t 'resources.managed-group.title_plural')}} + +{{outlet}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/index.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/index.hbs new file mode 100644 index 000000000..c482fd414 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/index.hbs @@ -0,0 +1,86 @@ +{{#if @model}} + + + + {{t 'form.name.label'}} + {{t 'form.description.label'}} + {{t 'form.type.label'}} + {{t 'form.id.label'}} + + + + + {{#each @model as |managed-group|}} + + + {{#if (can 'read model' managed-group)}} + + {{managed-group.displayName}} + + {{else}} + {{managed-group.displayName}} + {{/if}} + + {{managed-group.description}} + + {{managed-group.type}} + + + + {{managed-group.id}} + + + + {{/each}} + + +{{else}} + + + + + {{#if + (can 'list collection' this.authMethod collection='managed-groups') + }} + {{! Can list (at least): show default welcome message }} + {{t 'resources.managed-group.description'}} + {{else if (can + 'create collection' this.authMethod collection='managed-groups' + )}} + {{! Can create only: show create but not list welcome message }} + {{t + 'descriptions.create-but-not-list' + resource=(t 'resources.managed-group.title_plural') + }} + {{else}} + {{! Can neither list nor create }} + {{t + 'descriptions.neither-list-nor-create' + resource=(t 'resources.managed-group.title_plural') + }} + {{/if}} + + + {{#if + (can 'create collection' this.authMethod collection='managed-groups') + }} + + + {{t 'resources.managed-group.actions.create'}} + + {{/if}} + + +{{/if}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.hbs new file mode 100644 index 000000000..a6696c3b6 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group.hbs @@ -0,0 +1,2 @@ +{{page-title 'ManagedGroup'}} +{{outlet}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-actions.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-actions.hbs new file mode 100644 index 000000000..3340d97f2 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-actions.hbs @@ -0,0 +1,15 @@ +{{#if (can 'delete model' @model)}} + + + {{t 'resources.managed-group.actions.delete'}} + + +{{/if}} \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-header.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-header.hbs new file mode 100644 index 000000000..1e7ef1124 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-header.hbs @@ -0,0 +1,12 @@ +

+ {{t 'resources.managed-group.title'}} + +

+

{{t 'resources.managed-group.description'}}

+ + {{@model.id}} + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-navigation.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-navigation.hbs new file mode 100644 index 000000000..3a2ce54b7 --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/-navigation.hbs @@ -0,0 +1,7 @@ + + + {{t 'titles.details'}} + + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index.hbs new file mode 100644 index 000000000..bcaa893ac --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index.hbs @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/new.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/new.hbs new file mode 100644 index 000000000..bcaa893ac --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/new.hbs @@ -0,0 +1,5 @@ + \ No newline at end of file diff --git a/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/new/-header.hbs b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/new/-header.hbs new file mode 100644 index 000000000..b6e89205e --- /dev/null +++ b/ui/admin/app/templates/scopes/scope/auth-methods/auth-method/managed-groups/new/-header.hbs @@ -0,0 +1,5 @@ +

+ {{t 'titles.new'}} + {{! TODO: change the icon link }} + +

\ No newline at end of file diff --git a/ui/admin/config/environment.js b/ui/admin/config/environment.js index 771068764..613c6a3e8 100644 --- a/ui/admin/config/environment.js +++ b/ui/admin/config/environment.js @@ -48,6 +48,7 @@ module.exports = function (environment) { account: '/accounts', 'account.new': '/accounts/new', 'auth-method': '/auth-methods', + 'managed-groups': '/managed-groups', group: '/groups', 'group.add-members': '/groups/add-members', 'host-catalog': '/host-catalogs', @@ -96,6 +97,7 @@ module.exports = function (environment) { filter: false, capabilities: true, 'credential-store': true, + 'managed-groups': false, }, }; @@ -133,6 +135,7 @@ module.exports = function (environment) { // Enable features in development ENV.featureFlags['capabilities'] = true; ENV.featureFlags['filter'] = true; + ENV.featureFlags['managed-groups'] = true; } if (environment === 'test') { @@ -159,6 +162,7 @@ module.exports = function (environment) { // Enable tests for development features ENV.featureFlags['capabilities'] = true; ENV.featureFlags['filter'] = true; + ENV.featureFlags['managed-groups'] = true; } if (environment === 'production') { diff --git a/ui/admin/tests/acceptance/managed-groups/list-test.js b/ui/admin/tests/acceptance/managed-groups/list-test.js new file mode 100644 index 000000000..dc2ad9e98 --- /dev/null +++ b/ui/admin/tests/acceptance/managed-groups/list-test.js @@ -0,0 +1,92 @@ +import { module, test } from 'qunit'; +import { visit, click, find } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import setupMirage from 'ember-cli-mirage/test-support/setup-mirage'; +import { authenticateSession } from 'ember-simple-auth/test-support'; + +module('Acceptance | managed-groups | list', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + const instances = { + scopes: { + global: null, + org: null, + }, + authMethod: null, + managedGroup: null, + }; + const urls = { + orgScope: null, + authMethods: null, + managedGroups: null, + newManagedGroup: null, + managedGroup: null, + }; + + 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' }, + }); + instances.authMethod = this.server.create('auth-method', { + scope: instances.scopes.org, + type: 'oidc', + }); + instances.managedGroup = this.server.create('managed-group', { + scope: instances.scopes.org, + authMethod: instances.authMethod, + }); + // Generate route URLs for resources + urls.orgScope = `/scopes/${instances.scopes.org.id}`; + urls.authMethods = `${urls.orgScope}/auth-methods`; + urls.authMethod = `${urls.authMethods}/${instances.authMethod.id}`; + urls.managedGroups = `${urls.authMethod}/managed-groups`; + urls.newManagedGroup = `${urls.managedGroups}/new`; + urls.managedGroup = `${urls.managedGroups}/${instances.authMethod.id}`; + }); + + hooks.afterEach(async function () { + const notification = find('.rose-notification'); + if (notification) { + await click('.rose-notification-dismiss'); + } + }); + + test('User can navigate to managed groups with proper authorization', async function (assert) { + assert.expect(2); + await visit(urls.authMethod); + assert.ok( + instances.authMethod.authorized_collection_actions[ + 'managed-groups' + ].includes('list') + ); + assert.ok(find(`[href="${urls.managedGroups}"]`)); + }); + + test('User cannot navigate to index without either list or create actions', async function (assert) { + assert.expect(2); + instances.authMethod.authorized_collection_actions['managed-groups'] = []; + await visit(urls.authMethod); + assert.notOk( + instances.authMethod.authorized_collection_actions[ + 'managed-groups' + ].includes('list') + ); + assert.notOk(find(`[href="${urls.managedGroups}"]`)); + }); + + test('User can navigate to index with only create action', async function (assert) { + assert.expect(2); + instances.authMethod.authorized_collection_actions['managed-groups'] = [ + 'create', + ]; + await visit(urls.authMethod); + assert.ok(find(`[href="${urls.managedGroups}"]`)); + assert.ok( + find(`.rose-layout-page-actions [href="${urls.newManagedGroup}"]`) + ); + }); +}); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups-test.js b/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups-test.js new file mode 100644 index 000000000..7f976529b --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Controller | scopes/scope/auth-methods/auth-method/managed-groups', + function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/auth-methods/auth-method/managed-groups' + ); + assert.ok(controller); + }); + } +); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups/managed-group-test.js b/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups/managed-group-test.js new file mode 100644 index 000000000..22284a9cf --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups/managed-group-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Controller | scopes/scope/auth-methods/auth-method/managed-groups/managed-group', + function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/auth-methods/auth-method/managed-groups/managed-group' + ); + assert.ok(controller); + }); + } +); diff --git a/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups/new-test.js b/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups/new-test.js new file mode 100644 index 000000000..699d52e58 --- /dev/null +++ b/ui/admin/tests/unit/controllers/scopes/scope/auth-methods/auth-method/managed-groups/new-test.js @@ -0,0 +1,17 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Controller | scopes/scope/auth-methods/auth-method/managed-groups/new', + function (hooks) { + setupTest(hooks); + + // TODO: Replace this with your real tests. + test('it exists', function (assert) { + let controller = this.owner.lookup( + 'controller:scopes/scope/auth-methods/auth-method/managed-groups/new' + ); + assert.ok(controller); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups-test.js b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups-test.js new file mode 100644 index 000000000..cb0c40319 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/auth-methods/auth-method/managed-groups', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/auth-methods/auth-method/managed-groups' + ); + assert.ok(route); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/index-test.js b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/index-test.js new file mode 100644 index 000000000..269bb8663 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/index-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/auth-methods/auth-method/managed-groups/index', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/auth-methods/auth-method/managed-groups/index' + ); + assert.ok(route); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group-test.js b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group-test.js new file mode 100644 index 000000000..f323d5e2e --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/auth-methods/auth-method/managed-groups/managed-group', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/auth-methods/auth-method/managed-groups/managed-group' + ); + assert.ok(route); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index-test.js b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index-test.js new file mode 100644 index 000000000..47aadd91a --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/auth-methods/auth-method/managed-groups/managed-group/index' + ); + assert.ok(route); + }); + } +); diff --git a/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/new-test.js b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/new-test.js new file mode 100644 index 000000000..3ea26ad63 --- /dev/null +++ b/ui/admin/tests/unit/routes/scopes/scope/auth-methods/auth-method/managed-groups/new-test.js @@ -0,0 +1,16 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module( + 'Unit | Route | scopes/scope/auth-methods/auth-method/managed-groups/new', + function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup( + 'route:scopes/scope/auth-methods/auth-method/managed-groups/new' + ); + assert.ok(route); + }); + } +);