feat: 🎸 CRUDL capabilites for ldap managed-group (#1805)
* feat: 🎸 CRUDL capabilites for ldap managed-group ✅ Closes: ICU-10100 * refactor: 💡 managed-group serializer & remove members tab * refactor: 💡 show members tab * fix: 🐛 add type getters in managed group model * refactor: 💡 fix column name
This commit is contained in:
1 parent
e5a026ed34
commit
d49f3b72a6
19 files changed
+848
-301
No files matched your search
@@ -6,6 +6,7 @@
|
||||
import GeneratedManagedGroupModel from '../generated/models/managed-group';
|
||||
import { attr } from '@ember-data/model';
|
||||
import { A } from '@ember/array';
|
||||
import { TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP } from './auth-method';
|
||||
|
||||
export default class ManagedGroupModel extends GeneratedManagedGroupModel {
|
||||
// =attributes
|
||||
@@ -20,4 +21,18 @@ export default class ManagedGroupModel extends GeneratedManagedGroupModel {
|
||||
emptyArrayIfMissing: true,
|
||||
})
|
||||
member_ids;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isOIDC() {
|
||||
return this.type === TYPE_AUTH_METHOD_OIDC;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isLDAP() {
|
||||
return this.type === TYPE_AUTH_METHOD_LDAP;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,10 @@ import {
|
||||
|
||||
export default class ManagedGroupSerializer extends ApplicationSerializer {
|
||||
// =properties
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
serializeScopeID = false;
|
||||
|
||||
/**
|
||||
* Delegates to a type-specific serialization, or default.
|
||||
|
||||
@@ -794,6 +794,10 @@ managed-group:
|
||||
messages:
|
||||
title: Welcome to Members
|
||||
description: No members in this managed group.
|
||||
form:
|
||||
group_names:
|
||||
label: Group Names
|
||||
help: The list of groups that this Managed Group belongs to.
|
||||
worker:
|
||||
title: Worker
|
||||
title_pki: New PKI Worker
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
{{/if}}
|
||||
|
||||
{{#if (can 'create model' @model collection='managed-groups')}}
|
||||
{{#if @model.isOIDC}}
|
||||
{{#if (or @model.isOIDC @model.isLDAP)}}
|
||||
<dropdown.link
|
||||
@route='scopes.scope.auth-methods.auth-method.managed-groups.new'
|
||||
@model={{@model}}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
{{/if}}
|
||||
|
||||
{{#if (can 'navigate model' @model collection='managed-groups')}}
|
||||
{{#if @model.isOIDC}}
|
||||
{{#if (or @model.isOIDC @model.isLDAP)}}
|
||||
<nav.link @route='scopes.scope.auth-methods.auth-method.managed-groups'>
|
||||
{{t 'resources.managed-group.title_plural'}}
|
||||
</nav.link>
|
||||
|
||||
@@ -3,81 +3,14 @@
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.error.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<Hds::Form::Textarea::Field
|
||||
@isOptional={{true}}
|
||||
@value={{@model.description}}
|
||||
@isInvalid={{@model.errors.description}}
|
||||
name='description'
|
||||
disabled={{form.disabled}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'form.description.label'}}</F.Label>
|
||||
<F.HelperText>{{t 'form.description.help'}}</F.HelperText>
|
||||
{{#if @model.errors.description}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Textarea::Field>
|
||||
|
||||
<form.input
|
||||
@name='filter'
|
||||
@type='text'
|
||||
@value={{@model.filter_string}}
|
||||
@label={{t 'form.filter.label'}}
|
||||
@error={{@model.errors.filter_string}}
|
||||
@helperText={{t 'form.filter.help'}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.filter_string}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.filter_string as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
{{#if @model.type}}
|
||||
{{component
|
||||
(concat 'form/managed-group/' @model.type)
|
||||
model=@model
|
||||
edit=@edit
|
||||
submit=@submit
|
||||
cancel=@cancel
|
||||
removeItemByIndex=@removeItemByIndex
|
||||
addStringItem=@addStringItem
|
||||
}}
|
||||
{{/if}}
|
||||
@@ -0,0 +1,134 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Rose::Form
|
||||
@edit={{@edit}}
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<InfoField @value={{@model.type}} disabled={{form.disabled}} as |F|>
|
||||
<F.Label>{{t 'form.type.label'}}</F.Label>
|
||||
</InfoField>
|
||||
|
||||
<Hds::Form::TextInput::Field
|
||||
@isOptional={{true}}
|
||||
name='name'
|
||||
@value={{@model.name}}
|
||||
@isInvalid={{@model.errors.name}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'input' (set-from-event @model 'name')}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'form.name.label'}}</F.Label>
|
||||
<F.HelperText>{{t 'form.name.help'}}</F.HelperText>
|
||||
{{#if @model.errors.name}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::TextInput::Field>
|
||||
|
||||
<Hds::Form::Textarea::Field
|
||||
@isOptional={{true}}
|
||||
@value={{@model.description}}
|
||||
@isInvalid={{@model.errors.description}}
|
||||
name='description'
|
||||
disabled={{form.disabled}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'form.description.label'}}</F.Label>
|
||||
<F.HelperText>{{t 'form.description.help'}}</F.HelperText>
|
||||
{{#if @model.errors.description}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Textarea::Field>
|
||||
|
||||
<Hds::Form::Fieldset @isRequired={{true}} as |F|>
|
||||
<F.Legend>{{t 'resources.managed-group.form.group_names.label'}}</F.Legend>
|
||||
<F.HelperText>{{t
|
||||
'resources.managed-group.form.group_names.help'
|
||||
}}</F.HelperText>
|
||||
{{#let (unique-id) as |valueHeaderID|}}
|
||||
<F.Control>
|
||||
<Hds::Table class='key-value-list' name='group_names'>
|
||||
<:head as |H|>
|
||||
<H.Tr>
|
||||
<H.Th id={{valueHeaderID}}>{{t 'titles.value'}}</H.Th>
|
||||
<H.Th>{{t 'titles.actions'}}</H.Th>
|
||||
</H.Tr>
|
||||
</:head>
|
||||
<:body as |B|>
|
||||
{{#each @model.group_names as |group i|}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{group.value}}
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event group 'value')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.remove'}}
|
||||
@color='critical'
|
||||
@icon='trash'
|
||||
@isIconOnly={{true}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'click' (fn @removeItemByIndex 'group_names' i)}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
{{/each}}
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
<Hds::Form::TextInput::Field
|
||||
@value={{this.newGroup}}
|
||||
@type='text'
|
||||
disabled={{form.disabled}}
|
||||
aria-labelledby={{valueHeaderID}}
|
||||
{{on 'input' (set-from-event this 'newGroup')}}
|
||||
/>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
<Hds::Button
|
||||
@text={{t 'actions.add'}}
|
||||
@color='secondary'
|
||||
disabled={{or form.disabled (not this.newGroup)}}
|
||||
{{on 'click' this.addGroupName}}
|
||||
/>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
</F.Control>
|
||||
{{/let}}
|
||||
{{#if @model.errors.group_names}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.group_names as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Fieldset>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
</Rose::Form>
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) HashiCorp, Inc.
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*/
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
export default class FormManagedGroupLdapComponent extends Component {
|
||||
// =attributes
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@tracked newGroup = '';
|
||||
|
||||
@action
|
||||
addGroupName() {
|
||||
if (this.newGroup) {
|
||||
this.args.addStringItem('group_names', this.newGroup);
|
||||
}
|
||||
this.newGroup = '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{{!
|
||||
Copyright (c) HashiCorp, Inc.
|
||||
SPDX-License-Identifier: MPL-2.0
|
||||
}}
|
||||
|
||||
<Rose::Form
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
@showEditToggle={{if @model.isNew false true}}
|
||||
as |form|
|
||||
>
|
||||
<form.input
|
||||
@value={{@model.type}}
|
||||
@label={{t 'form.type.label'}}
|
||||
readonly={{true}}
|
||||
@disabled={{true}}
|
||||
/>
|
||||
|
||||
<form.input
|
||||
@name='name'
|
||||
@type='name'
|
||||
@value={{@model.name}}
|
||||
@label={{t 'form.name.label'}}
|
||||
@helperText={{t 'form.name.help'}}
|
||||
@error={{@model.error.name}}
|
||||
readonly={{false}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.name}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.name as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
<Hds::Form::Textarea::Field
|
||||
@isOptional={{true}}
|
||||
@value={{@model.description}}
|
||||
@isInvalid={{@model.errors.description}}
|
||||
name='description'
|
||||
disabled={{form.disabled}}
|
||||
as |F|
|
||||
>
|
||||
<F.Label>{{t 'form.description.label'}}</F.Label>
|
||||
<F.HelperText>{{t 'form.description.help'}}</F.HelperText>
|
||||
{{#if @model.errors.description}}
|
||||
<F.Error as |E|>
|
||||
{{#each @model.errors.description as |error|}}
|
||||
<E.Message>{{error.message}}</E.Message>
|
||||
{{/each}}
|
||||
</F.Error>
|
||||
{{/if}}
|
||||
</Hds::Form::Textarea::Field>
|
||||
|
||||
<form.input
|
||||
@name='filter'
|
||||
@type='text'
|
||||
@value={{@model.filter_string}}
|
||||
@label={{t 'form.filter.label'}}
|
||||
@error={{@model.errors.filter_string}}
|
||||
@helperText={{t 'form.filter.help'}}
|
||||
as |field|
|
||||
>
|
||||
{{#if @model.errors.filter_string}}
|
||||
<field.errors as |errors|>
|
||||
{{#each @model.errors.filter_string as |error|}}
|
||||
<errors.message>{{error.message}}</errors.message>
|
||||
{{/each}}
|
||||
</field.errors>
|
||||
{{/if}}
|
||||
</form.input>
|
||||
|
||||
{{#if (can 'save model' @model)}}
|
||||
<form.actions
|
||||
@enableEditText={{t 'actions.edit-form'}}
|
||||
@submitText={{t 'actions.save'}}
|
||||
@cancelText={{t 'actions.cancel'}}
|
||||
/>
|
||||
{{/if}}
|
||||
</Rose::Form>
|
||||
+18
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
|
||||
export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsManagedGroupRoute extends Route {
|
||||
@@ -24,4 +25,21 @@ export default class ScopesScopeAuthMethodsAuthMethodManagedGroupsManagedGroupRo
|
||||
reload: true,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the contents of string array fields in order to force the instance
|
||||
* into a dirty state. This ensures that `model.rollbackAttributes()` reverts
|
||||
* to the original expected array.
|
||||
*
|
||||
* The deep copy implemented here is required to ensure that both the
|
||||
* array itself and its members are all new.
|
||||
*
|
||||
* @param {managedGroupModel} managedGroup
|
||||
*/
|
||||
@action
|
||||
edit(managedGroup) {
|
||||
if (managedGroup.group_names) {
|
||||
managedGroup.group_names = structuredClone(managedGroup.group_names);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@
|
||||
<Hds::Table
|
||||
@model={{@model.accounts}}
|
||||
@columns={{array
|
||||
(hash label=(t 'resources.account.form.login_name.label'))
|
||||
(hash label=(t 'form.name.label'))
|
||||
(hash label=(t 'resources.account.form.email.label'))
|
||||
(hash label=(t 'resources.account.form.full_name.label'))
|
||||
(hash label=(t 'resources.account.form.dn.label'))
|
||||
|
||||
+72
-31
@@ -23,48 +23,89 @@
|
||||
|
||||
<page.body>
|
||||
{{#if @model.managedGroups}}
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t 'form.name.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.description.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.type.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.id.label'}}</row.headerCell>
|
||||
</header.row>
|
||||
</table.header>
|
||||
|
||||
<table.body as |body|>
|
||||
{{#each @model.managedGroups as |managed-group|}}
|
||||
<body.row as |row|>
|
||||
<row.headerCell>
|
||||
{{#if (can 'read model' managed-group)}}
|
||||
{{#if @model.managedGroups.firstObject.isOIDC}}
|
||||
<Hds::Table
|
||||
@model={{@model.managedGroups}}
|
||||
@columns={{array
|
||||
(hash label=(t 'form.name.label'))
|
||||
(hash label=(t 'form.description.label'))
|
||||
(hash label=(t 'form.type.label'))
|
||||
(hash label=(t 'form.id.label'))
|
||||
}}
|
||||
@valign='middle'
|
||||
>
|
||||
<:body as |B|>
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
{{#if (can 'read model' B.data)}}
|
||||
<LinkTo
|
||||
@route='scopes.scope.auth-methods.auth-method.managed-groups.managed-group'
|
||||
@model={{managed-group.id}}
|
||||
@model={{B.data.id}}
|
||||
>
|
||||
{{managed-group.displayName}}
|
||||
{{B.data.displayName}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
{{managed-group.displayName}}
|
||||
{{B.data.displayName}}
|
||||
{{/if}}
|
||||
</row.headerCell>
|
||||
<row.cell>{{managed-group.description}}</row.cell>
|
||||
<row.cell>
|
||||
<Hds::Badge @text={{managed-group.type}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
</B.Td>
|
||||
<B.Td>{{B.data.description}}</B.Td>
|
||||
<B.Td><Hds::Badge @text={{B.data.type}} /></B.Td>
|
||||
<B.Td>
|
||||
<Copyable
|
||||
@text={{managed-group.id}}
|
||||
@text={{B.data.id}}
|
||||
@buttonText={{t 'actions.copy-to-clipboard'}}
|
||||
@acknowledgeText={{t 'states.copied'}}
|
||||
>
|
||||
<code>{{managed-group.id}}</code>
|
||||
<code>{{B.data.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
{{else}}
|
||||
<Hds::Table
|
||||
@model={{@model.managedGroups}}
|
||||
@columns={{array
|
||||
(hash label=(t 'form.name.label'))
|
||||
(hash label=(t 'form.description.label'))
|
||||
(hash label=(t 'form.type.label'))
|
||||
(hash label=(t 'form.id.label'))
|
||||
(hash label=(t 'resources.managed-group.form.group_names.label'))
|
||||
}}
|
||||
@valign='middle'
|
||||
>
|
||||
<:body as |B|>
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
{{#if (can 'read model' B.data)}}
|
||||
<LinkTo
|
||||
@route='scopes.scope.auth-methods.auth-method.managed-groups.managed-group'
|
||||
@model={{B.data.id}}
|
||||
>
|
||||
{{B.data.displayName}}
|
||||
</LinkTo>
|
||||
{{else}}
|
||||
{{B.data.displayName}}
|
||||
{{/if}}
|
||||
</B.Td>
|
||||
<B.Td>{{B.data.description}}</B.Td>
|
||||
<B.Td><Hds::Badge @text={{B.data.type}} /></B.Td>
|
||||
<B.Td>
|
||||
<Copyable
|
||||
@text={{B.data.id}}
|
||||
@buttonText={{t 'actions.copy-to-clipboard'}}
|
||||
@acknowledgeText={{t 'states.copied'}}
|
||||
>
|
||||
<code>{{B.data.id}}</code>
|
||||
</Copyable>
|
||||
</B.Td>
|
||||
<B.Td>
|
||||
{{truncate-list 'actions.more' B.data.group_names 3}}
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message
|
||||
|
||||
+3
@@ -30,8 +30,11 @@
|
||||
<page.body>
|
||||
<Form::ManagedGroup
|
||||
@model={{@model}}
|
||||
@edit={{route-action 'edit' @model}}
|
||||
@submit={{route-action 'save' @model}}
|
||||
@cancel={{route-action 'cancel' @model}}
|
||||
@removeItemByIndex={{route-action 'removeItemByIndex' @model}}
|
||||
@addStringItem={{route-action 'addStringItem' @model}}
|
||||
/>
|
||||
</page.body>
|
||||
|
||||
|
||||
+62
-42
@@ -31,53 +31,73 @@
|
||||
|
||||
<page.body>
|
||||
{{#if @model.members}}
|
||||
<Rose::Table as |table|>
|
||||
<table.header as |header|>
|
||||
<header.row as |row|>
|
||||
<row.headerCell>{{t 'form.name.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.issuer.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.subject.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.email.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.full_name.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.type.label'}}</row.headerCell>
|
||||
<row.headerCell>{{t 'form.id.label'}}</row.headerCell>
|
||||
</header.row>
|
||||
</table.header>
|
||||
<table.body as |body|>
|
||||
{{#each @model.members as |member|}}
|
||||
<body.row as |row|>
|
||||
<row.headerCell scope='row'>
|
||||
{{member.accountName}}
|
||||
<p>{{member.description}}</p>
|
||||
</row.headerCell>
|
||||
<row.cell>
|
||||
<code>{{member.issuer}}</code>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<code>{{member.subject}}</code>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<code>{{member.email}}</code>
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
{{member.full_name}}
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
<Hds::Badge @text={{member.type}} />
|
||||
</row.cell>
|
||||
<row.cell>
|
||||
{{#if @model.members.firstObject.isOIDC}}
|
||||
<Hds::Table
|
||||
@model={{@model.members}}
|
||||
@columns={{array
|
||||
(hash label=(t 'form.name.label'))
|
||||
(hash label=(t 'form.issuer.label'))
|
||||
(hash label=(t 'form.subject.label'))
|
||||
(hash label=(t 'form.email.label'))
|
||||
(hash label=(t 'form.full_name.label'))
|
||||
(hash label=(t 'form.type.label'))
|
||||
(hash label=(t 'form.id.label'))
|
||||
}}
|
||||
@valign='middle'
|
||||
>
|
||||
<:body as |B|>
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
{{B.data.accountName}}
|
||||
<p>{{B.data.description}}</p>
|
||||
</B.Td>
|
||||
<B.Td>{{B.data.issuer}}</B.Td>
|
||||
<B.Td>{{B.data.subject}}</B.Td>
|
||||
<B.Td>{{B.data.email}}</B.Td>
|
||||
<B.Td>{{B.data.full_name}}</B.Td>
|
||||
<B.Td><Hds::Badge @text={{B.data.type}} /></B.Td>
|
||||
<B.Td>
|
||||
<Copyable
|
||||
@text={{member.id}}
|
||||
@text={{B.data.id}}
|
||||
@buttonText={{t 'actions.copy-to-clipboard'}}
|
||||
@acknowledgeText={{t 'states.copied'}}
|
||||
>
|
||||
<code>{{member.id}}</code>
|
||||
<code>{{B.data.id}}</code>
|
||||
</Copyable>
|
||||
</row.cell>
|
||||
</body.row>
|
||||
{{/each}}
|
||||
</table.body>
|
||||
</Rose::Table>
|
||||
</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
{{else}}
|
||||
<Hds::Table
|
||||
@model={{@model.members}}
|
||||
@columns={{array
|
||||
(hash label=(t 'form.name.label'))
|
||||
(hash label=(t 'resources.account.form.email.label'))
|
||||
(hash label=(t 'resources.account.form.full_name.label'))
|
||||
(hash label=(t 'resources.account.form.dn.label'))
|
||||
(hash label=(t 'resources.account.form.member_of_groups.label'))
|
||||
}}
|
||||
@valign='middle'
|
||||
>
|
||||
<:body as |B|>
|
||||
<B.Tr>
|
||||
<B.Td>
|
||||
{{B.data.displayName}}
|
||||
<p>{{B.data.description}}</p>
|
||||
</B.Td>
|
||||
<B.Td>{{B.data.email}}</B.Td>
|
||||
<B.Td>{{B.data.full_name}}</B.Td>
|
||||
<B.Td>{{B.data.dn}}</B.Td>
|
||||
<B.Td>{{truncate-list
|
||||
'actions.more'
|
||||
B.data.member_of_groups
|
||||
3
|
||||
}}</B.Td>
|
||||
</B.Tr>
|
||||
</:body>
|
||||
</Hds::Table>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<Rose::Layout::Centered>
|
||||
<Rose::Message
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
<page.header>
|
||||
<h2>
|
||||
{{t 'titles.new'}}
|
||||
{{! TODO: change the icon link }}
|
||||
<DocLink @doc='account.new' @iconSize='large' />
|
||||
<DocLink @doc='managed-groups' @iconSize='large' />
|
||||
</h2>
|
||||
</page.header>
|
||||
|
||||
@@ -22,6 +21,8 @@
|
||||
@model={{@model}}
|
||||
@submit={{route-action 'save' @model}}
|
||||
@cancel={{route-action 'cancel' @model}}
|
||||
@removeItemByIndex={{route-action 'removeItemByIndex' @model}}
|
||||
@addStringItem={{route-action 'addStringItem' @model}}
|
||||
/>
|
||||
</page.body>
|
||||
|
||||
|
||||
@@ -4,32 +4,48 @@
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, currentURL, click, find, fillIn } from '@ember/test-helpers';
|
||||
import { visit, currentURL, click, fillIn } 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';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { Response } from 'miragejs';
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Acceptance | managed-groups | create', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let getManagedGroupCount;
|
||||
let featuresService;
|
||||
|
||||
const SAVE_BTN_SELECTOR = '.rose-form-actions [type="submit"]';
|
||||
const CANCEL_BTN_SELECTOR = '.rose-form-actions [type="button"]';
|
||||
const NAME_INPUT_SELECTOR = '[name="name"]';
|
||||
const DESC_INPUT_SELECTOR = '[name="description"]';
|
||||
const ERROR_MSG_SELECTOR = '.rose-notification-body';
|
||||
const FIELD_ERROR_TEXT_SELECTOR = '.hds-form-error__message';
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authMethod: null,
|
||||
managedGroup: null,
|
||||
ldapAuthMethod: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
authMethods: null,
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroups: null,
|
||||
ldapManagedGroups: null,
|
||||
newManagedGroup: null,
|
||||
managedGroup: null,
|
||||
newLdapManagedGroup: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -43,93 +59,126 @@ module('Acceptance | managed-groups | create', function (hooks) {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
instances.managedGroup = this.server.create('managed-group', {
|
||||
instances.ldapAuthMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
authMethod: instances.authMethod,
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
|
||||
// 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.ldapAuthMethod = `${urls.authMethods}/${instances.ldapAuthMethod.id}`;
|
||||
urls.managedGroups = `${urls.authMethod}/managed-groups`;
|
||||
urls.ldapManagedGroups = `${urls.ldapAuthMethod}/managed-groups`;
|
||||
urls.newManagedGroup = `${urls.managedGroups}/new`;
|
||||
urls.managedGroup = `${urls.managedGroups}/${instances.authMethod.id}`;
|
||||
});
|
||||
urls.newLdapManagedGroup = `${urls.ldapManagedGroups}/new`;
|
||||
|
||||
hooks.afterEach(async function () {
|
||||
const notification = find('.rose-notification');
|
||||
if (notification) {
|
||||
await click('.rose-notification-dismiss');
|
||||
}
|
||||
});
|
||||
|
||||
test('visiting managed groups', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.managedGroups);
|
||||
await a11yAudit();
|
||||
assert.strictEqual(currentURL(), urls.managedGroups);
|
||||
getManagedGroupCount = () =>
|
||||
this.server.schema.managedGroups.all().models.length;
|
||||
featuresService = this.owner.lookup('service:features');
|
||||
});
|
||||
|
||||
test('can create a new managed group', async function (assert) {
|
||||
assert.expect(1);
|
||||
const managedGroupsCount = this.server.db.managedGroups.length;
|
||||
await visit(urls.newManagedGroup);
|
||||
await fillIn('[name="name"]', 'Managed group name');
|
||||
await fillIn('[name="description"]', 'description');
|
||||
await click('form [type="submit"]:not(:disabled)');
|
||||
assert.strictEqual(
|
||||
this.server.db.managedGroups.length,
|
||||
managedGroupsCount + 1
|
||||
);
|
||||
});
|
||||
|
||||
test('User can not create a new managed group without proper authorization', async function (assert) {
|
||||
assert.expect(2);
|
||||
instances.authMethod.authorized_collection_actions['managed-groups'] = [];
|
||||
assert.expect(3);
|
||||
const managedGroupsCount = getManagedGroupCount();
|
||||
const name = 'Managed group name';
|
||||
await visit(urls.authMethod);
|
||||
assert.notOk(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.notOk(
|
||||
find(`.rose-layout-page-actions [href="${urls.newManagedGroup}"]`)
|
||||
);
|
||||
|
||||
await click(`[href="${urls.newManagedGroup}"]`);
|
||||
await fillIn(NAME_INPUT_SELECTOR, name);
|
||||
await fillIn(DESC_INPUT_SELECTOR, 'description');
|
||||
await click(SAVE_BTN_SELECTOR);
|
||||
|
||||
const managedGroup = this.server.schema.managedGroups.findBy({ name });
|
||||
assert.strictEqual(managedGroup.name, name);
|
||||
assert.strictEqual(managedGroup.description, 'description');
|
||||
assert.strictEqual(getManagedGroupCount(), managedGroupsCount + 1);
|
||||
});
|
||||
|
||||
test('User can navigate to new managed group route with proper authorization', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(urls.managedGroups);
|
||||
assert.ok(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.ok(find(`[href="${urls.newManagedGroup}"]`));
|
||||
test('can create a new ldap managed group', async function (assert) {
|
||||
assert.expect(4);
|
||||
const managedGroupsCount = getManagedGroupCount();
|
||||
const name = 'Managed group name';
|
||||
await visit(urls.ldapAuthMethod);
|
||||
|
||||
await click(`[href="${urls.newLdapManagedGroup}"]`);
|
||||
await fillIn(NAME_INPUT_SELECTOR, name);
|
||||
await fillIn(DESC_INPUT_SELECTOR, 'description');
|
||||
await fillIn('[name="group_names"] input', 'group name');
|
||||
await click('[name="group_names"] button');
|
||||
await click(SAVE_BTN_SELECTOR);
|
||||
|
||||
const managedGroup = this.server.schema.managedGroups.findBy({ name });
|
||||
assert.strictEqual(managedGroup.name, name);
|
||||
assert.strictEqual(managedGroup.description, 'description');
|
||||
assert.deepEqual(managedGroup.attributes.group_names, ['group name']);
|
||||
assert.strictEqual(getManagedGroupCount(), managedGroupsCount + 1);
|
||||
});
|
||||
|
||||
test('User cannot navigate to new managed group route without proper authorization', async function (assert) {
|
||||
test('User cannot create a new managed group without proper authorization', async function (assert) {
|
||||
assert.expect(2);
|
||||
instances.authMethod.authorized_collection_actions['managed-groups'] = [];
|
||||
await visit(urls.managedGroups);
|
||||
assert.notOk(
|
||||
instances.authMethod.authorized_collection_actions['managed-groups'] =
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].filter((item) => item !== 'create');
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.authMethod}"]`);
|
||||
|
||||
assert.false(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.notOk(find(`[href="${urls.newManagedGroup}"]`));
|
||||
assert.dom(`[href="${urls.newManagedGroup}"]`).doesNotExist();
|
||||
});
|
||||
|
||||
test('User cannot create a new ldap managed group without proper authorization', async function (assert) {
|
||||
assert.expect(2);
|
||||
featuresService.enable('ldap-auth-methods');
|
||||
instances.ldapAuthMethod.authorized_collection_actions['managed-groups'] =
|
||||
instances.ldapAuthMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].filter((item) => item !== 'create');
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.ldapAuthMethod}"]`);
|
||||
|
||||
assert.false(
|
||||
instances.ldapAuthMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.dom(`[href="${urls.newLdapManagedGroup}"]`).doesNotExist();
|
||||
});
|
||||
|
||||
test('User can cancel a new managed group creation', async function (assert) {
|
||||
assert.expect(2);
|
||||
const managedGroupsCount = this.server.db.managedGroups.length;
|
||||
await visit(urls.newManagedGroup);
|
||||
await fillIn('[name="name"]', 'Managed group name');
|
||||
await click('form button:not([type="submit"])');
|
||||
assert.strictEqual(this.server.db.managedGroups.length, managedGroupsCount);
|
||||
const managedGroupsCount = getManagedGroupCount();
|
||||
await visit(urls.authMethod);
|
||||
|
||||
await click(`[href="${urls.newManagedGroup}"]`);
|
||||
await fillIn(NAME_INPUT_SELECTOR, 'Managed group name');
|
||||
await click(CANCEL_BTN_SELECTOR);
|
||||
|
||||
assert.strictEqual(getManagedGroupCount(), managedGroupsCount);
|
||||
assert.strictEqual(currentURL(), urls.managedGroups);
|
||||
});
|
||||
|
||||
test('User can cancel a new ldap managed group creation', async function (assert) {
|
||||
assert.expect(2);
|
||||
const managedGroupsCount = getManagedGroupCount();
|
||||
await visit(urls.ldapAuthMethod);
|
||||
|
||||
await click(`[href="${urls.newLdapManagedGroup}"]`);
|
||||
await fillIn(NAME_INPUT_SELECTOR, 'Managed group name');
|
||||
await click(CANCEL_BTN_SELECTOR);
|
||||
|
||||
assert.strictEqual(getManagedGroupCount(), managedGroupsCount);
|
||||
assert.strictEqual(currentURL(), urls.ldapManagedGroups);
|
||||
});
|
||||
|
||||
test('When user saving a new managed group with invalid fields displays error message', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.server.post('/managed-groups', () => {
|
||||
@@ -151,19 +200,46 @@ module('Acceptance | managed-groups | create', function (hooks) {
|
||||
}
|
||||
);
|
||||
});
|
||||
await visit(urls.newManagedGroup);
|
||||
await fillIn('[name="name"]', 'new managed group');
|
||||
await click('form [type="submit"]');
|
||||
await visit(urls.authMethod);
|
||||
|
||||
await click(`[href="${urls.newManagedGroup}"]`);
|
||||
await fillIn(NAME_INPUT_SELECTOR, 'new managed group');
|
||||
await click(SAVE_BTN_SELECTOR);
|
||||
await a11yAudit();
|
||||
assert.strictEqual(
|
||||
find('.rose-notification-body').textContent.trim(),
|
||||
'The request was invalid.',
|
||||
'Displays primary error message.'
|
||||
);
|
||||
assert.strictEqual(
|
||||
find('.rose-form-error-message').textContent.trim(),
|
||||
'Name is required.',
|
||||
'Displays field-level errors.'
|
||||
);
|
||||
|
||||
assert.dom(ERROR_MSG_SELECTOR).hasText('The request was invalid.');
|
||||
assert.dom('.rose-form-error-message').hasText('Name is required.');
|
||||
});
|
||||
|
||||
test('When user saving a new ldap managed group with invalid fields displays error message', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.server.post('/managed-groups', () => {
|
||||
return new Response(
|
||||
400,
|
||||
{},
|
||||
{
|
||||
status: 400,
|
||||
code: 'invalid_argument',
|
||||
message: 'The request was invalid.',
|
||||
details: {
|
||||
request_fields: [
|
||||
{
|
||||
name: 'name',
|
||||
description: 'Name is required.',
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
await visit(urls.ldapAuthMethod);
|
||||
|
||||
await click(`[href="${urls.newLdapManagedGroup}"]`);
|
||||
await fillIn(NAME_INPUT_SELECTOR, 'new managed group');
|
||||
await click(SAVE_BTN_SELECTOR);
|
||||
await a11yAudit();
|
||||
|
||||
assert.dom(ERROR_MSG_SELECTOR).hasText('The request was invalid.');
|
||||
assert.dom(FIELD_ERROR_TEXT_SELECTOR).hasText('Name is required.');
|
||||
});
|
||||
});
|
||||
@@ -4,32 +4,47 @@
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, click, find } from '@ember/test-helpers';
|
||||
import { visit, click, currentURL } 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';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { Response } from 'miragejs';
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Acceptance | managed-groups | delete', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let getManagedGroupCount;
|
||||
|
||||
const DELETE_DROPDOWN_SELECTOR =
|
||||
'.rose-layout-page-actions .rose-dropdown-button-danger';
|
||||
const ERROR_MSG_SELECTOR = '.rose-notification-body';
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroup: null,
|
||||
ldapManagedGroup: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
authMethods: null,
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroups: null,
|
||||
newManagedGroup: null,
|
||||
ldapManagedGroups: null,
|
||||
managedGroup: null,
|
||||
ldapManagedGroup: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -43,36 +58,54 @@ module('Acceptance | managed-groups | delete', function (hooks) {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
instances.ldapAuthMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
instances.managedGroup = this.server.create('managed-group', {
|
||||
scope: instances.scopes.org,
|
||||
authMethod: instances.authMethod,
|
||||
});
|
||||
instances.ldapManagedGroup = this.server.create('managed-group', {
|
||||
scope: instances.scopes.org,
|
||||
authMethod: instances.ldapAuthMethod,
|
||||
});
|
||||
// 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.ldapAuthMethod = `${urls.authMethods}/${instances.ldapAuthMethod.id}`;
|
||||
urls.managedGroups = `${urls.authMethod}/managed-groups`;
|
||||
urls.newManagedGroup = `${urls.managedGroups}/new`;
|
||||
// TODO refactor in the rest of the test this url
|
||||
urls.ldapManagedGroups = `${urls.ldapAuthMethod}/managed-groups`;
|
||||
urls.managedGroup = `${urls.managedGroups}/${instances.managedGroup.id}`;
|
||||
});
|
||||
urls.ldapManagedGroup = `${urls.ldapManagedGroups}/${instances.ldapManagedGroup.id}`;
|
||||
|
||||
hooks.afterEach(async function () {
|
||||
const notification = find('.rose-notification');
|
||||
if (notification) {
|
||||
await click('.rose-notification-dismiss');
|
||||
}
|
||||
getManagedGroupCount = () =>
|
||||
this.server.schema.managedGroups.all().models.length;
|
||||
});
|
||||
|
||||
test('User can delete a managed group', async function (assert) {
|
||||
assert.expect(1);
|
||||
const managedGroupsCount = this.server.db.managedGroups.length;
|
||||
await visit(urls.managedGroup);
|
||||
await click('.rose-layout-page-actions .rose-dropdown-button-danger');
|
||||
assert.strictEqual(
|
||||
this.server.db.managedGroups.length,
|
||||
managedGroupsCount - 1
|
||||
);
|
||||
assert.expect(2);
|
||||
const managedGroupsCount = getManagedGroupCount();
|
||||
await visit(urls.managedGroups);
|
||||
|
||||
await click(`[href="${urls.managedGroup}"]`);
|
||||
await click(DELETE_DROPDOWN_SELECTOR);
|
||||
|
||||
assert.strictEqual(getManagedGroupCount(), managedGroupsCount - 1);
|
||||
assert.strictEqual(currentURL(), urls.managedGroups);
|
||||
});
|
||||
|
||||
test('User can delete a ldap managed group', async function (assert) {
|
||||
assert.expect(2);
|
||||
const managedGroupsCount = getManagedGroupCount();
|
||||
await visit(urls.ldapManagedGroups);
|
||||
|
||||
await click(`[href="${urls.ldapManagedGroup}"]`);
|
||||
await click(DELETE_DROPDOWN_SELECTOR);
|
||||
|
||||
assert.strictEqual(getManagedGroupCount(), managedGroupsCount - 1);
|
||||
assert.strictEqual(currentURL(), urls.ldapManagedGroups);
|
||||
});
|
||||
|
||||
test('User cannot delete a managed-group without proper authorization', async function (assert) {
|
||||
@@ -81,14 +114,28 @@ module('Acceptance | managed-groups | delete', function (hooks) {
|
||||
instances.managedGroup.authorized_actions.filter(
|
||||
(item) => item !== 'delete'
|
||||
);
|
||||
await visit(urls.managedGroup);
|
||||
assert.notOk(
|
||||
find('.rose-layout-page-actions .rose-dropdown-button-danger')
|
||||
);
|
||||
await visit(urls.managedGroups);
|
||||
|
||||
await click(`[href="${urls.managedGroup}"]`);
|
||||
|
||||
assert.dom(DELETE_DROPDOWN_SELECTOR).doesNotExist();
|
||||
});
|
||||
|
||||
test('User cannot delete a ldap managed-group without proper authorization', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.ldapManagedGroup.authorized_actions =
|
||||
instances.ldapManagedGroup.authorized_actions.filter(
|
||||
(item) => item !== 'delete'
|
||||
);
|
||||
await visit(urls.ldapManagedGroups);
|
||||
|
||||
await click(`[href="${urls.ldapManagedGroup}"]`);
|
||||
|
||||
assert.dom(DELETE_DROPDOWN_SELECTOR).doesNotExist();
|
||||
});
|
||||
|
||||
test('Errors are displayed when delete on managed group fails', async function (assert) {
|
||||
assert.expect(1);
|
||||
assert.expect(2);
|
||||
this.server.del('/managed-groups/:id', () => {
|
||||
return new Response(
|
||||
490,
|
||||
@@ -100,13 +147,36 @@ module('Acceptance | managed-groups | delete', function (hooks) {
|
||||
}
|
||||
);
|
||||
});
|
||||
await visit(urls.managedGroup);
|
||||
await click('.rose-layout-page-actions .rose-dropdown-button-danger');
|
||||
await visit(urls.managedGroups);
|
||||
|
||||
await click(`[href="${urls.managedGroup}"]`);
|
||||
await click(DELETE_DROPDOWN_SELECTOR);
|
||||
await a11yAudit();
|
||||
assert.strictEqual(
|
||||
find('.rose-notification-body').textContent.trim(),
|
||||
'Oops.',
|
||||
'Displays primary error message.'
|
||||
);
|
||||
|
||||
assert.dom(ERROR_MSG_SELECTOR).hasText('Oops.');
|
||||
assert.strictEqual(currentURL(), urls.managedGroup);
|
||||
});
|
||||
|
||||
test('Errors are displayed when delete on ldap managed group fails', async function (assert) {
|
||||
assert.expect(2);
|
||||
this.server.del('/managed-groups/:id', () => {
|
||||
return new Response(
|
||||
490,
|
||||
{},
|
||||
{
|
||||
status: 490,
|
||||
code: 'error',
|
||||
message: 'Oops.',
|
||||
}
|
||||
);
|
||||
});
|
||||
await visit(urls.ldapManagedGroups);
|
||||
|
||||
await click(`[href="${urls.ldapManagedGroup}"]`);
|
||||
await click(DELETE_DROPDOWN_SELECTOR);
|
||||
await a11yAudit();
|
||||
|
||||
assert.dom(ERROR_MSG_SELECTOR).hasText('Oops.');
|
||||
assert.strictEqual(currentURL(), urls.ldapManagedGroup);
|
||||
});
|
||||
});
|
||||
@@ -4,30 +4,39 @@
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, click, find } from '@ember/test-helpers';
|
||||
import { visit, click } 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';
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Acceptance | managed-groups | list', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
|
||||
let featuresService;
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
global: null,
|
||||
org: null,
|
||||
},
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroup: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
authMethods: null,
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroups: null,
|
||||
ldapManagedGroups: null,
|
||||
newManagedGroup: null,
|
||||
managedGroup: null,
|
||||
newLdapManagedGroup: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -41,47 +50,106 @@ module('Acceptance | managed-groups | list', function (hooks) {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
instances.ldapAuthMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
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.ldapAuthMethod = `${urls.authMethods}/${instances.ldapAuthMethod.id}`;
|
||||
urls.managedGroups = `${urls.authMethod}/managed-groups`;
|
||||
urls.ldapManagedGroups = `${urls.ldapAuthMethod}/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');
|
||||
}
|
||||
urls.newLdapManagedGroup = `${urls.ldapManagedGroups}/new`;
|
||||
featuresService = this.owner.lookup('service:features');
|
||||
});
|
||||
|
||||
test('User can navigate to managed groups with proper authorization', async function (assert) {
|
||||
assert.expect(2);
|
||||
await visit(urls.authMethod);
|
||||
assert.ok(
|
||||
assert.expect(3);
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.authMethod}"]`);
|
||||
|
||||
assert.true(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('list')
|
||||
);
|
||||
assert.ok(find(`[href="${urls.managedGroups}"]`));
|
||||
assert.true(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.dom(`[href="${urls.managedGroups}"]`).exists();
|
||||
});
|
||||
|
||||
test('User can navigate to ldap managed groups with proper authorization', async function (assert) {
|
||||
assert.expect(3);
|
||||
featuresService.enable('ldap-auth-methods');
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.ldapAuthMethod}"]`);
|
||||
|
||||
assert.true(
|
||||
instances.ldapAuthMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('list')
|
||||
);
|
||||
assert.true(
|
||||
instances.ldapAuthMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.dom(`[href="${urls.ldapManagedGroups}"]`).exists();
|
||||
});
|
||||
|
||||
test('User cannot navigate to index without either list or create actions', async function (assert) {
|
||||
assert.expect(2);
|
||||
assert.expect(3);
|
||||
instances.authMethod.authorized_collection_actions['managed-groups'] = [];
|
||||
await visit(urls.authMethod);
|
||||
assert.notOk(
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.authMethod}"]`);
|
||||
|
||||
assert.false(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('list')
|
||||
);
|
||||
assert.notOk(find(`[href="${urls.managedGroups}"]`));
|
||||
assert.false(
|
||||
instances.authMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.dom(`[href="${urls.managedGroups}"]`).doesNotExist();
|
||||
});
|
||||
|
||||
test('User cannot navigate to ldap managed group index without either list or create actions', async function (assert) {
|
||||
assert.expect(3);
|
||||
featuresService.enable('ldap-auth-methods');
|
||||
instances.ldapAuthMethod.authorized_collection_actions['managed-groups'] =
|
||||
[];
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.ldapAuthMethod}"]`);
|
||||
|
||||
assert.false(
|
||||
instances.ldapAuthMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('list')
|
||||
);
|
||||
assert.false(
|
||||
instances.ldapAuthMethod.authorized_collection_actions[
|
||||
'managed-groups'
|
||||
].includes('create')
|
||||
);
|
||||
assert.dom(`[href="${urls.ldapManagedGroups}"]`).doesNotExist();
|
||||
});
|
||||
|
||||
test('User can navigate to index with only create action', async function (assert) {
|
||||
@@ -89,10 +157,25 @@ module('Acceptance | managed-groups | list', function (hooks) {
|
||||
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}"]`)
|
||||
);
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.authMethod}"]`);
|
||||
|
||||
assert.dom(`[href="${urls.managedGroups}"]`).exists();
|
||||
assert.dom(`[href="${urls.newManagedGroup}"]`).exists();
|
||||
});
|
||||
|
||||
test('User can navigate to ldap managed groups index with only create action', async function (assert) {
|
||||
assert.expect(2);
|
||||
featuresService.enable('ldap-auth-methods');
|
||||
instances.authMethod.authorized_collection_actions['managed-groups'] = [
|
||||
'create',
|
||||
];
|
||||
await visit(urls.authMethods);
|
||||
|
||||
await click(`[href="${urls.ldapAuthMethod}"]`);
|
||||
|
||||
assert.dom(`[href="${urls.ldapManagedGroups}"]`).exists();
|
||||
assert.dom(`[href="${urls.newLdapManagedGroup}"]`).exists();
|
||||
});
|
||||
});
|
||||
@@ -4,12 +4,15 @@
|
||||
*/
|
||||
|
||||
import { module, test } from 'qunit';
|
||||
import { visit, click, find, currentURL } from '@ember/test-helpers';
|
||||
import { visit, click, currentURL } 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';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { TYPE_AUTH_METHOD_OIDC } from 'api/models/auth-method';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
module('Acceptance | managed-groups | read', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
@@ -21,14 +24,19 @@ module('Acceptance | managed-groups | read', function (hooks) {
|
||||
org: null,
|
||||
},
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroup: null,
|
||||
ldapManagedGroup: null,
|
||||
};
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
authMethods: null,
|
||||
authMethod: null,
|
||||
ldapAuthMethod: null,
|
||||
managedGroups: null,
|
||||
newManagedGroup: null,
|
||||
ldapManagedGroups: null,
|
||||
managedGroup: null,
|
||||
ldapManagedGroup: null,
|
||||
};
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
@@ -42,42 +50,72 @@ module('Acceptance | managed-groups | read', function (hooks) {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_OIDC,
|
||||
});
|
||||
instances.ldapAuthMethod = this.server.create('auth-method', {
|
||||
scope: instances.scopes.org,
|
||||
type: TYPE_AUTH_METHOD_LDAP,
|
||||
});
|
||||
instances.managedGroup = this.server.create('managed-group', {
|
||||
scope: instances.scopes.org,
|
||||
authMethod: instances.authMethod,
|
||||
});
|
||||
instances.ldapManagedGroup = this.server.create('managed-group', {
|
||||
scope: instances.scopes.org,
|
||||
authMethod: instances.ldapAuthMethod,
|
||||
});
|
||||
// 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.ldapAuthMethod = `${urls.authMethods}/${instances.ldapAuthMethod.id}`;
|
||||
urls.managedGroups = `${urls.authMethod}/managed-groups`;
|
||||
urls.newManagedGroup = `${urls.managedGroups}/new`;
|
||||
// TODO refactor in the rest of the test this url
|
||||
urls.ldapManagedGroups = `${urls.ldapAuthMethod}/managed-groups`;
|
||||
urls.managedGroup = `${urls.managedGroups}/${instances.managedGroup.id}`;
|
||||
});
|
||||
|
||||
hooks.afterEach(async function () {
|
||||
const notification = find('.rose-notification');
|
||||
if (notification) {
|
||||
await click('.rose-notification-dismiss');
|
||||
}
|
||||
urls.ldapManagedGroup = `${urls.ldapManagedGroups}/${instances.ldapManagedGroup.id}`;
|
||||
});
|
||||
|
||||
test('User can navigate to a managed group form', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.managedGroups);
|
||||
await click('main tbody .rose-table-header-cell:nth-child(1) a');
|
||||
|
||||
await click(`[href="${urls.managedGroup}"]`);
|
||||
await a11yAudit();
|
||||
|
||||
assert.strictEqual(currentURL(), urls.managedGroup);
|
||||
});
|
||||
|
||||
test('User can navigate to a ldap managed group form', async function (assert) {
|
||||
assert.expect(1);
|
||||
await visit(urls.ldapManagedGroups);
|
||||
|
||||
await click(`[href="${urls.ldapManagedGroup}"]`);
|
||||
await a11yAudit();
|
||||
|
||||
assert.strictEqual(currentURL(), urls.ldapManagedGroup);
|
||||
});
|
||||
|
||||
test('User cannot navigate to a managed group form without proper authorization', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.managedGroup.authorized_actions =
|
||||
instances.managedGroup.authorized_actions.filter(
|
||||
(item) => item !== 'read'
|
||||
);
|
||||
await visit(urls.managedGroups);
|
||||
assert.notOk(find('main tbody .rose-table-header-cell:nth-child(1) a'));
|
||||
await visit(urls.authMethod);
|
||||
|
||||
await click(`[href="${urls.managedGroups}"]`);
|
||||
|
||||
assert.dom(`[href="${urls.managedGroup}"]`).doesNotExist();
|
||||
});
|
||||
|
||||
test('User cannot navigate to a ldap managed group form without proper authorization', async function (assert) {
|
||||
assert.expect(1);
|
||||
instances.ldapManagedGroup.authorized_actions =
|
||||
instances.ldapManagedGroup.authorized_actions.filter(
|
||||
(item) => item !== 'read'
|
||||
);
|
||||
await visit(urls.ldapAuthMethod);
|
||||
|
||||
await click(`[href="${urls.ldapManagedGroups}"]`);
|
||||
|
||||
assert.dom(`[href="${urls.ldapManagedGroup}"]`).doesNotExist();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user