ICU-14496 add discard unsaved changes modal to manage scopes (#2421)
* refactor: 💡 add discard unsaved changes modal ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-14496
This commit is contained in:
1 parent
a7d9a7e348
commit
7ac904a31f
20 files changed
+331
-98
No files matched your search
@@ -6,7 +6,7 @@
|
||||
{{#if @model.totalItemsCount}}
|
||||
<Rose::Form
|
||||
class='full-width role-manage-custom-scopes-form'
|
||||
@onSubmit={{fn @submit this.allGrantScopes}}
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.role.isSaving}}
|
||||
as |form|
|
||||
@@ -21,12 +21,12 @@
|
||||
/>
|
||||
</Hds::SegmentedGroup>
|
||||
{{#if @model.orgScopes}}
|
||||
{{#if this.selectedItems.length}}
|
||||
{{#if @model.role.grantScopeOrgIDs.length}}
|
||||
<div class='table-selected-items-text'>
|
||||
<Hds::Text::Body @tag='p' @color='faint'>
|
||||
{{t
|
||||
'resources.role.scope.titles.selected'
|
||||
items=this.selectedItems.length
|
||||
items=@model.role.grantScopeOrgIDs.length
|
||||
total=@model.totalItemsCount
|
||||
}}
|
||||
</Hds::Text::Body>
|
||||
@@ -46,7 +46,7 @@
|
||||
<:body as |B|>
|
||||
<B.Tr
|
||||
@selectionKey={{B.data.id}}
|
||||
@isSelected={{includes B.data.id this.selectedItems}}
|
||||
@isSelected={{includes B.data.id @model.role.grantScopeOrgIDs}}
|
||||
@selectionAriaLabelSuffix='row {{B.data.id}}'
|
||||
data-test-org-scopes-table-row={{B.data.id}}
|
||||
>
|
||||
|
||||
@@ -5,21 +5,8 @@
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
export default class FormRoleManageCustomScopesIndexComponent extends Component {
|
||||
// =attributes
|
||||
|
||||
@tracked selectedItems = [...this.args.model.role.grantScopeOrgIDs];
|
||||
|
||||
get allGrantScopes() {
|
||||
return [
|
||||
...this.args.model.role.grantScopeKeywords,
|
||||
...this.args.model.role.grantScopeProjectIDs,
|
||||
...this.selectedItems,
|
||||
];
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
@@ -28,15 +15,16 @@ export default class FormRoleManageCustomScopesIndexComponent extends Component
|
||||
*/
|
||||
@action
|
||||
selectionChange({ selectableRowsStates }) {
|
||||
const { role } = this.args.model;
|
||||
selectableRowsStates.forEach((row) => {
|
||||
const { isSelected, selectionKey: key } = row;
|
||||
const includesId = this.selectedItems.includes(key);
|
||||
if (isSelected) {
|
||||
if (!includesId) this.selectedItems = [...this.selectedItems, key];
|
||||
} else if (includesId) {
|
||||
this.selectedItems = this.selectedItems.filter(
|
||||
(item) => item !== key,
|
||||
);
|
||||
const includesId = role.grant_scope_ids.includes(key);
|
||||
if (isSelected && !includesId) {
|
||||
role.grant_scope_ids = [...role.grant_scope_ids, key];
|
||||
} else if (!isSelected && includesId) {
|
||||
role.grant_scope_ids = role.grant_scope_ids.filter(
|
||||
(item) => item !== key,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{{#if @model.totalItemsCount}}
|
||||
<Rose::Form
|
||||
class='full-width role-manage-custom-scopes-form'
|
||||
@onSubmit={{fn @submit this.allGrantScopes}}
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.role.isSaving}}
|
||||
as |form|
|
||||
@@ -21,12 +21,12 @@
|
||||
/>
|
||||
</Hds::SegmentedGroup>
|
||||
{{#if @model.projectScopes}}
|
||||
{{#if this.selectedItems.length}}
|
||||
{{#if this.selectedProjectsCount}}
|
||||
<div class='table-selected-items-text'>
|
||||
<Hds::Text::Body @tag='p' @color='faint'>
|
||||
{{t
|
||||
'resources.role.scope.titles.selected'
|
||||
items=this.selectedItems.length
|
||||
items=this.selectedProjectsCount
|
||||
total=@model.totalItemsCount
|
||||
}}
|
||||
</Hds::Text::Body>
|
||||
@@ -45,7 +45,7 @@
|
||||
<:body as |B|>
|
||||
<B.Tr
|
||||
@selectionKey={{B.data.id}}
|
||||
@isSelected={{includes B.data.id this.selectedItems}}
|
||||
@isSelected={{includes B.data.id @model.role.grant_scope_ids}}
|
||||
@selectionAriaLabelSuffix='row {{B.data.id}}'
|
||||
data-test-project-scopes-table-row={{B.data.id}}
|
||||
>
|
||||
|
||||
@@ -5,20 +5,13 @@
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
|
||||
export default class FormRoleManageOrgProjectsIndexComponent extends Component {
|
||||
// =attributes
|
||||
|
||||
@tracked selectedItems = [...this.args.model.selectedProjectIDs];
|
||||
|
||||
get allGrantScopes() {
|
||||
return [
|
||||
...this.args.model.role.grantScopeKeywords,
|
||||
...this.args.model.role.grantScopeOrgIDs,
|
||||
...this.args.model.remainingProjectIDs,
|
||||
...this.selectedItems,
|
||||
];
|
||||
get selectedProjectsCount() {
|
||||
const { role, remainingProjectIDs } = this.args.model;
|
||||
return role.grantScopeProjectIDs.length - remainingProjectIDs.length;
|
||||
}
|
||||
|
||||
// =actions
|
||||
@@ -29,16 +22,16 @@ export default class FormRoleManageOrgProjectsIndexComponent extends Component {
|
||||
*/
|
||||
@action
|
||||
selectionChange({ selectableRowsStates }) {
|
||||
const { role } = this.args.model;
|
||||
selectableRowsStates.forEach((row) => {
|
||||
const { isSelected, selectionKey: key } = row;
|
||||
const includesId = this.selectedItems.includes(key);
|
||||
if (isSelected) {
|
||||
if (!includesId) this.selectedItems = [...this.selectedItems, key];
|
||||
} else {
|
||||
if (includesId)
|
||||
this.selectedItems = this.selectedItems.filter(
|
||||
(item) => item !== key,
|
||||
);
|
||||
const includesId = role.grant_scope_ids.includes(key);
|
||||
if (isSelected && !includesId) {
|
||||
role.grant_scope_ids = [...role.grant_scope_ids, key];
|
||||
} else if (!isSelected && includesId) {
|
||||
role.grant_scope_ids = role.grant_scope_ids.filter(
|
||||
(item) => item !== key,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<Rose::Form
|
||||
class='full-width role-manage-scopes-form'
|
||||
@onSubmit={{fn @submit this.selectedItems}}
|
||||
@onSubmit={{@submit}}
|
||||
@cancel={{@cancel}}
|
||||
@disabled={{@model.isSaving}}
|
||||
as |form|
|
||||
@@ -14,7 +14,7 @@
|
||||
<Hds::Form::Toggle::Field
|
||||
@value={{this.keywords.keyThis}}
|
||||
name={{this.keywords.keyThis}}
|
||||
checked={{includes this.keywords.keyThis this.selectedItems}}
|
||||
checked={{includes this.keywords.keyThis @model.grant_scope_ids}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' this.toggleField}}
|
||||
as |F|
|
||||
@@ -31,7 +31,7 @@
|
||||
<Hds::Form::Toggle::Field
|
||||
@value={{this.keywords.keyChildren}}
|
||||
name={{this.keywords.keyChildren}}
|
||||
checked={{includes this.keywords.keyChildren this.selectedItems}}
|
||||
checked={{includes this.keywords.keyChildren @model.grant_scope_ids}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' this.toggleField}}
|
||||
as |F|
|
||||
@@ -48,7 +48,7 @@
|
||||
<Hds::Form::Toggle::Field
|
||||
@value={{this.keywords.keyDescendants}}
|
||||
name={{this.keywords.keyDescendants}}
|
||||
checked={{includes this.keywords.keyDescendants this.selectedItems}}
|
||||
checked={{includes this.keywords.keyDescendants @model.grant_scope_ids}}
|
||||
disabled={{form.disabled}}
|
||||
{{on 'change' this.toggleField}}
|
||||
as |F|
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import Component from '@glimmer/component';
|
||||
import { action } from '@ember/object';
|
||||
import { tracked } from '@glimmer/tracking';
|
||||
import {
|
||||
GRANT_SCOPE_THIS,
|
||||
GRANT_SCOPE_CHILDREN,
|
||||
@@ -21,8 +20,6 @@ export default class FormRoleManageScopesIndexComponent extends Component {
|
||||
keyDescendants: GRANT_SCOPE_DESCENDANTS,
|
||||
};
|
||||
|
||||
@tracked selectedItems = [...this.args.model.grant_scope_ids];
|
||||
|
||||
/**
|
||||
* Returns true if role is global level and either
|
||||
* "children" or "descendants" is toggled on.
|
||||
@@ -31,8 +28,8 @@ export default class FormRoleManageScopesIndexComponent extends Component {
|
||||
get showAlert() {
|
||||
return (
|
||||
this.args.model.scope.isGlobal &&
|
||||
(this.selectedItems.includes(GRANT_SCOPE_CHILDREN) ||
|
||||
this.selectedItems.includes(GRANT_SCOPE_DESCENDANTS))
|
||||
(this.args.model.grant_scope_ids.includes(GRANT_SCOPE_CHILDREN) ||
|
||||
this.args.model.grant_scope_ids.includes(GRANT_SCOPE_DESCENDANTS))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -46,10 +43,15 @@ export default class FormRoleManageScopesIndexComponent extends Component {
|
||||
toggleField(event) {
|
||||
const { checked, value } = event.target;
|
||||
const removeValue = (value) => {
|
||||
this.selectedItems = this.selectedItems.filter((item) => item !== value);
|
||||
this.args.model.grant_scope_ids = this.args.model.grant_scope_ids.filter(
|
||||
(item) => item !== value,
|
||||
);
|
||||
};
|
||||
if (checked) {
|
||||
this.selectedItems = [...this.selectedItems, value];
|
||||
this.args.model.grant_scope_ids = [
|
||||
...this.args.model.grant_scope_ids,
|
||||
value,
|
||||
];
|
||||
if (value === GRANT_SCOPE_CHILDREN) {
|
||||
removeValue(GRANT_SCOPE_DESCENDANTS);
|
||||
}
|
||||
|
||||
@@ -23,22 +23,23 @@ export default class ScopesScopeRolesRoleManageScopesIndexController extends Con
|
||||
/**
|
||||
* Save grant scope IDs to current role via the API.
|
||||
* @param {RoleModel} role
|
||||
* @param {[string]} grantScopeIDs
|
||||
*/
|
||||
@action
|
||||
@loading
|
||||
@notifyError(({ message }) => message, { catch: true })
|
||||
@notifySuccess('resources.role.scope.messages.manage-scopes.success')
|
||||
async setGrantScopes(role, grantScopeIDs) {
|
||||
await role.setGrantScopes(grantScopeIDs);
|
||||
async setGrantScopes(role) {
|
||||
await role.setGrantScopes(role.grant_scope_ids);
|
||||
this.router.replaceWith('scopes.scope.roles.role.scopes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to role scopes as if nothing ever happened.
|
||||
* @param {RoleModel} role
|
||||
*/
|
||||
@action
|
||||
cancel() {
|
||||
cancel(role) {
|
||||
role.rollbackAttributes();
|
||||
this.router.replaceWith('scopes.scope.roles.role.scopes');
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -43,23 +43,24 @@ export default class ScopesScopeRolesRoleManageScopesManageCustomScopesControlle
|
||||
/**
|
||||
* Save grant scope IDs to current role via the API.
|
||||
* @param {RoleModel} role
|
||||
* @param {[string]} grantScopeIDs
|
||||
*/
|
||||
@action
|
||||
@loading
|
||||
@notifyError(({ message }) => message, { catch: true })
|
||||
@notifySuccess('resources.role.scope.messages.manage-custom-scopes.success')
|
||||
async setGrantScopes(role, grantScopeIDs) {
|
||||
await role.setGrantScopes(grantScopeIDs);
|
||||
async setGrantScopes(role) {
|
||||
await role.setGrantScopes(role.grant_scope_ids);
|
||||
this.manageScopes.showCheckIcon = true;
|
||||
await this.router.replaceWith('scopes.scope.roles.role.manage-scopes');
|
||||
this.router.replaceWith('scopes.scope.roles.role.manage-scopes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to manage scopes as if nothing ever happened.
|
||||
* @param {RoleModel} role
|
||||
*/
|
||||
@action
|
||||
async cancel() {
|
||||
await this.router.replaceWith('scopes.scope.roles.role.manage-scopes');
|
||||
cancel(role) {
|
||||
role.rollbackAttributes();
|
||||
this.router.replaceWith('scopes.scope.roles.role.manage-scopes');
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -43,14 +43,13 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsController
|
||||
/**
|
||||
* Save grant scope IDs to current role via the API.
|
||||
* @param {RoleModel} role
|
||||
* @param {[string]} grantScopeIDs
|
||||
*/
|
||||
@action
|
||||
@loading
|
||||
@notifyError(({ message }) => message, { catch: true })
|
||||
@notifySuccess('resources.role.scope.messages.manage-org-projects.success')
|
||||
async setGrantScopes(role, grantScopeIDs) {
|
||||
await role.setGrantScopes(grantScopeIDs);
|
||||
async setGrantScopes(role) {
|
||||
await role.setGrantScopes(role.grant_scope_ids);
|
||||
this.manageScopes.showCheckIcon = true;
|
||||
if (role.scope.isGlobal) {
|
||||
this.router.replaceWith(
|
||||
@@ -63,9 +62,11 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsController
|
||||
|
||||
/**
|
||||
* Redirect to previous as if nothing ever happened.
|
||||
* @param {RoleModel} role
|
||||
*/
|
||||
@action
|
||||
cancel(role) {
|
||||
role.rollbackAttributes();
|
||||
if (role.scope.isGlobal) {
|
||||
this.router.replaceWith(
|
||||
'scopes.scope.roles.role.manage-scopes.manage-custom-scopes',
|
||||
|
||||
@@ -43,7 +43,8 @@ export default class ApplicationRoute extends Route {
|
||||
this.router.on('routeWillChange', async (transition) => {
|
||||
const fromName = transition?.from?.name;
|
||||
const toName = transition?.to?.name;
|
||||
const maybeModel = transition?.from?.attributes;
|
||||
const maybeModel =
|
||||
transition?.data?.model ?? transition?.from?.attributes;
|
||||
if (fromName !== toName && maybeModel?.hasDirtyAttributes) {
|
||||
transition.abort();
|
||||
try {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import Route from '@ember/routing/route';
|
||||
import { action } from '@ember/object';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { TYPE_SCOPE_PROJECT } from 'api/models/scope';
|
||||
|
||||
@@ -26,6 +27,8 @@ export default class ScopesScopeRolesRoleManageScopesManageCustomScopesRoute ext
|
||||
// =services
|
||||
|
||||
@service store;
|
||||
@service intl;
|
||||
@service confirm;
|
||||
|
||||
// =methods
|
||||
|
||||
@@ -128,4 +131,17 @@ export default class ScopesScopeRolesRoleManageScopesManageCustomScopesRoute ext
|
||||
);
|
||||
return scopes.meta?.totalItems;
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* Stores the role model in the transition data property so that the application level hook
|
||||
* can check for dirty attributes and trigger the confirm service.
|
||||
* @param {object} transition
|
||||
*/
|
||||
@action
|
||||
async willTransition(transition) {
|
||||
const { role } = transition.from.attributes;
|
||||
transition.data = { model: role };
|
||||
}
|
||||
}
|
||||
@@ -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 ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute extends Route {
|
||||
@@ -25,12 +26,14 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute exte
|
||||
// =services
|
||||
|
||||
@service store;
|
||||
@service intl;
|
||||
@service confirm;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Loads projects for current org scope.
|
||||
* @return {Promise<{role: RoleModel, orgScope: ScopeModel, projectScopes: [ScopeModel], totalItems: number, totalItemsCount: number, selectedProjectIDs: [string], remainingProjectIDs: [string]}> }
|
||||
* @return {Promise<{role: RoleModel, orgScope: ScopeModel, projectScopes: [ScopeModel], totalItems: number, totalItemsCount: number, remainingProjectIDs: [string]}> }
|
||||
*/
|
||||
async model({ org_id, search, page, pageSize }) {
|
||||
const role = this.modelFor('scopes.scope.roles.role');
|
||||
@@ -53,8 +56,7 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute exte
|
||||
totalItems,
|
||||
);
|
||||
|
||||
const { selectedProjectIDs, remainingProjectIDs } =
|
||||
await this.getSelectedProjects(role, org_id);
|
||||
const remainingProjectIDs = await this.getRemainingProjects(role, org_id);
|
||||
|
||||
return {
|
||||
role,
|
||||
@@ -62,7 +64,6 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute exte
|
||||
projectScopes,
|
||||
totalItems,
|
||||
totalItemsCount,
|
||||
selectedProjectIDs,
|
||||
remainingProjectIDs,
|
||||
};
|
||||
}
|
||||
@@ -98,12 +99,12 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute exte
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract project type grant scope ids that belong to this org scope.
|
||||
* Extract project type grant scope ids that don't belong to this org scope.
|
||||
* @param {RoleModel} role
|
||||
* @param {string} org_id
|
||||
* @returns {object}
|
||||
* @returns {Promise<[string]>} remainingProjectIDs
|
||||
*/
|
||||
async getSelectedProjects(role, org_id) {
|
||||
async getRemainingProjects(role, org_id) {
|
||||
let selectedProjectIDs = role.grantScopeProjectIDs;
|
||||
let remainingProjectIDs = [];
|
||||
if (role.scope.isGlobal && selectedProjectIDs.length) {
|
||||
@@ -115,15 +116,25 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute exte
|
||||
{ scope_id: 'global', query: { filters: { id } } },
|
||||
options,
|
||||
);
|
||||
selectedProjectIDs = projects.reduce((selectedIDs, project) => {
|
||||
if (project.scope.id === org_id) {
|
||||
selectedIDs.push(project.id);
|
||||
} else {
|
||||
projects.forEach((project) => {
|
||||
if (project.scope.id !== org_id) {
|
||||
remainingProjectIDs.push(project.id);
|
||||
}
|
||||
return selectedIDs;
|
||||
}, []);
|
||||
});
|
||||
}
|
||||
return { selectedProjectIDs, remainingProjectIDs };
|
||||
return remainingProjectIDs;
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
* Stores the role model in the transition data property so that the application level hook
|
||||
* can check for dirty attributes and trigger the confirm service.
|
||||
* @param {object} transition
|
||||
*/
|
||||
@action
|
||||
async willTransition(transition) {
|
||||
const { role } = transition.from.attributes;
|
||||
transition.data = { model: role };
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
@model={{@model}}
|
||||
@showCheckIcon={{this.showCheckIcon}}
|
||||
@submit={{fn this.setGrantScopes @model}}
|
||||
@cancel={{this.cancel}}
|
||||
@cancel={{fn this.cancel @model}}
|
||||
/>
|
||||
</page.body>
|
||||
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@
|
||||
@pageSize={{this.pageSize}}
|
||||
@handleSearchInput={{this.handleSearchInput}}
|
||||
@submit={{fn this.setGrantScopes @model.role}}
|
||||
@cancel={{this.cancel}}
|
||||
@cancel={{fn this.cancel @model.role}}
|
||||
/>
|
||||
</page.body>
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
@search={{this.search}}
|
||||
@page={{this.page}}
|
||||
@pageSize={{this.pageSize}}
|
||||
@selectedItems={{this.selectedItems}}
|
||||
@handleSearchInput={{this.handleSearchInput}}
|
||||
@submit={{fn this.setGrantScopes @model.role}}
|
||||
@cancel={{fn this.cancel @model.role}}
|
||||
|
||||
@@ -29,6 +29,8 @@ module('Acceptance | roles | global-scope', function (hooks) {
|
||||
setupMirage(hooks);
|
||||
setupIndexedDb(hooks);
|
||||
|
||||
let confirmService;
|
||||
|
||||
const SCOPE_TOGGLE_SELECTOR = (name) =>
|
||||
`.hds-form-toggle input[name="${name}"]`;
|
||||
const SCOPE_CHECKBOX_SELECTOR = (type, id) =>
|
||||
@@ -55,6 +57,11 @@ module('Acceptance | roles | global-scope', function (hooks) {
|
||||
const BUTTON_ICON_SELECTOR =
|
||||
'.hds-button__icon [data-test-icon="check-circle"]';
|
||||
const PAGINATION_SELECTOR = '.hds-pagination';
|
||||
const DISCARD_CHANGES_DIALOG = '.rose-dialog';
|
||||
const DISCARD_CHANGES_DISCARD_BUTTON =
|
||||
'.rose-dialog-footer .rose-button-primary';
|
||||
const DISCARD_CHANGES_CANCEL_BUTTON =
|
||||
'.rose-dialog-footer .rose-button-secondary';
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
@@ -75,6 +82,8 @@ module('Acceptance | roles | global-scope', function (hooks) {
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
authenticateSession({});
|
||||
confirmService = this.owner.lookup('service:confirm');
|
||||
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
@@ -345,6 +354,40 @@ module('Acceptance | roles | global-scope', function (hooks) {
|
||||
assert.dom(TOAST_SELECTOR).isVisible();
|
||||
});
|
||||
|
||||
test('user is prompted to confirm exit when there are unsaved changes on manage scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.role);
|
||||
|
||||
await click(MANAGE_DROPDOWN_SELECTOR);
|
||||
await click(MANAGE_SCOPES_SELECTOR);
|
||||
await click(SCOPE_TOGGLE_SELECTOR(GRANT_SCOPE_THIS));
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_DISCARD_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.roles);
|
||||
});
|
||||
|
||||
test('user user can cancel transition when there are unsaved changes on manage scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.role);
|
||||
|
||||
await click(MANAGE_DROPDOWN_SELECTOR);
|
||||
await click(MANAGE_SCOPES_SELECTOR);
|
||||
await click(SCOPE_TOGGLE_SELECTOR(GRANT_SCOPE_THIS));
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_CANCEL_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.manageScopes);
|
||||
});
|
||||
|
||||
test('user can save custom scopes to add on manage custom scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
await visit(urls.role);
|
||||
@@ -432,6 +475,40 @@ module('Acceptance | roles | global-scope', function (hooks) {
|
||||
assert.dom(TOAST_SELECTOR).isVisible();
|
||||
});
|
||||
|
||||
test('user is prompted to confirm exit when there are unsaved changes on manage custom scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.manageScopes);
|
||||
|
||||
await click(`[href="${urls.manageCustomScopes}"]`);
|
||||
await click(SCOPE_CHECKBOX_SELECTOR('org', instances.scopes.org.id));
|
||||
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_DISCARD_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.roles);
|
||||
});
|
||||
|
||||
test('user user can cancel transition when there are unsaved changes on manage custom scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.manageScopes);
|
||||
|
||||
await click(`[href="${urls.manageCustomScopes}"]`);
|
||||
await click(SCOPE_CHECKBOX_SELECTOR('org', instances.scopes.org.id));
|
||||
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_CANCEL_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.manageCustomScopes);
|
||||
});
|
||||
|
||||
test('user can search for a specific org scope by id on manage custom scopes page', async function (assert) {
|
||||
const anotherOrg = this.server.create('scope', {
|
||||
type: 'org',
|
||||
@@ -591,6 +668,51 @@ module('Acceptance | roles | global-scope', function (hooks) {
|
||||
assert.dom(TOAST_SELECTOR).isVisible();
|
||||
});
|
||||
|
||||
test('user is prompted to confirm exit when there are unsaved changes on manage org projects page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.manageScopes);
|
||||
|
||||
await click(`[href="${urls.manageCustomScopes}"]`);
|
||||
await click(
|
||||
`tbody [href="${urls.manageScopes}/${instances.scopes.org.id}"]`,
|
||||
);
|
||||
await click(
|
||||
SCOPE_CHECKBOX_SELECTOR('project', instances.scopes.project.id),
|
||||
);
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_DISCARD_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.roles);
|
||||
});
|
||||
|
||||
test('user user can cancel transition when there are unsaved changes on manage org projects page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.manageScopes);
|
||||
|
||||
await click(`[href="${urls.manageCustomScopes}"]`);
|
||||
await click(
|
||||
`tbody [href="${urls.manageScopes}/${instances.scopes.org.id}"]`,
|
||||
);
|
||||
await click(
|
||||
SCOPE_CHECKBOX_SELECTOR('project', instances.scopes.project.id),
|
||||
);
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_CANCEL_BUTTON);
|
||||
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
`${urls.manageScopes}/${instances.scopes.org.id}`,
|
||||
);
|
||||
});
|
||||
|
||||
test('user can search for a specific project scope by id on manage org projects page', async function (assert) {
|
||||
const anotherProject = this.server.create('scope', {
|
||||
type: 'project',
|
||||
|
||||
@@ -28,6 +28,8 @@ module('Acceptance | roles | org-scope', function (hooks) {
|
||||
setupMirage(hooks);
|
||||
setupIndexedDb(hooks);
|
||||
|
||||
let confirmService;
|
||||
|
||||
const SCOPE_TOGGLE_SELECTOR = (name) =>
|
||||
`.hds-form-toggle input[name="${name}"]`;
|
||||
const SCOPE_CHECKBOX_SELECTOR = (type, id) =>
|
||||
@@ -52,6 +54,11 @@ module('Acceptance | roles | org-scope', function (hooks) {
|
||||
const BUTTON_ICON_SELECTOR =
|
||||
'.hds-button__icon [data-test-icon="check-circle"]';
|
||||
const PAGINATION_SELECTOR = '.hds-pagination';
|
||||
const DISCARD_CHANGES_DIALOG = '.rose-dialog';
|
||||
const DISCARD_CHANGES_DISCARD_BUTTON =
|
||||
'.rose-dialog-footer .rose-button-primary';
|
||||
const DISCARD_CHANGES_CANCEL_BUTTON =
|
||||
'.rose-dialog-footer .rose-button-secondary';
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
@@ -61,6 +68,7 @@ module('Acceptance | roles | org-scope', function (hooks) {
|
||||
},
|
||||
role: null,
|
||||
};
|
||||
|
||||
const urls = {
|
||||
orgScope: null,
|
||||
roles: null,
|
||||
@@ -72,6 +80,8 @@ module('Acceptance | roles | org-scope', function (hooks) {
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
authenticateSession({});
|
||||
confirmService = this.owner.lookup('service:confirm');
|
||||
|
||||
instances.scopes.global = this.server.create('scope', { id: 'global' });
|
||||
instances.scopes.org = this.server.create('scope', {
|
||||
type: 'org',
|
||||
@@ -300,6 +310,40 @@ module('Acceptance | roles | org-scope', function (hooks) {
|
||||
assert.dom(TOAST_SELECTOR).isVisible();
|
||||
});
|
||||
|
||||
test('user is prompted to confirm exit when there are unsaved changes on manage scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.role);
|
||||
|
||||
await click(MANAGE_DROPDOWN_SELECTOR);
|
||||
await click(MANAGE_SCOPES_SELECTOR);
|
||||
await click(SCOPE_TOGGLE_SELECTOR(GRANT_SCOPE_THIS));
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_DISCARD_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.roles);
|
||||
});
|
||||
|
||||
test('user user can cancel transition when there are unsaved changes on manage scopes page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.role);
|
||||
|
||||
await click(MANAGE_DROPDOWN_SELECTOR);
|
||||
await click(MANAGE_SCOPES_SELECTOR);
|
||||
await click(SCOPE_TOGGLE_SELECTOR(GRANT_SCOPE_THIS));
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_CANCEL_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.manageScopes);
|
||||
});
|
||||
|
||||
test('user can save custom scopes to add on manage org projects page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
await visit(urls.role);
|
||||
@@ -394,6 +438,42 @@ module('Acceptance | roles | org-scope', function (hooks) {
|
||||
assert.dom(TOAST_SELECTOR).isVisible();
|
||||
});
|
||||
|
||||
test('user is prompted to confirm exit when there are unsaved changes on manage org projects page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.manageScopes);
|
||||
|
||||
await click(`[href="${urls.manageOrgProjects}"]`);
|
||||
await click(
|
||||
SCOPE_CHECKBOX_SELECTOR('project', instances.scopes.project.id),
|
||||
);
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_DISCARD_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.roles);
|
||||
});
|
||||
|
||||
test('user user can cancel transition when there are unsaved changes on manage org projects page', async function (assert) {
|
||||
instances.role.update({ grant_scope_ids: [] });
|
||||
confirmService.enabled = true;
|
||||
await visit(urls.manageScopes);
|
||||
|
||||
await click(`[href="${urls.manageOrgProjects}"]`);
|
||||
await click(
|
||||
SCOPE_CHECKBOX_SELECTOR('project', instances.scopes.project.id),
|
||||
);
|
||||
await click(`[href="${urls.roles}"]`);
|
||||
|
||||
assert.dom(DISCARD_CHANGES_DIALOG).isVisible();
|
||||
|
||||
await click(DISCARD_CHANGES_CANCEL_BUTTON);
|
||||
|
||||
assert.strictEqual(currentURL(), urls.manageOrgProjects);
|
||||
});
|
||||
|
||||
test('user can search for a specific project scope by id on manage org projects page', async function (assert) {
|
||||
const anotherProject = this.server.create('scope', {
|
||||
type: 'project',
|
||||
|
||||
+10
-3
@@ -8,6 +8,7 @@ import { setupTest } from 'ember-qunit';
|
||||
import { visit, currentURL, waitUntil } from '@ember/test-helpers';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { authenticateSession } from 'ember-simple-auth/test-support';
|
||||
import { GRANT_SCOPE_THIS } from 'api/models/role';
|
||||
|
||||
module(
|
||||
'Unit | Controller | scopes/scope/roles/role/manage-scopes/index',
|
||||
@@ -59,17 +60,23 @@ module(
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
|
||||
await controller.setGrantScopes(role, ['this']);
|
||||
role.grant_scope_ids = [GRANT_SCOPE_THIS];
|
||||
await controller.setGrantScopes(role);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, ['this']);
|
||||
assert.deepEqual(role.grant_scope_ids, [GRANT_SCOPE_THIS]);
|
||||
});
|
||||
|
||||
test('cancel action causes transition to expected route', async function (assert) {
|
||||
await visit(urls.manageScopes);
|
||||
const role = await store.findRecord('role', instances.role.id);
|
||||
|
||||
controller.cancel();
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
|
||||
role.grant_scope_ids = [GRANT_SCOPE_THIS];
|
||||
controller.cancel(role);
|
||||
await waitUntil(() => currentURL() === urls.scopes);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
assert.strictEqual(currentURL(), urls.scopes);
|
||||
});
|
||||
},
|
||||
|
||||
+9
-3
@@ -75,16 +75,22 @@ module(
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
|
||||
await controller.setGrantScopes(role, [instances.scopes.org.id]);
|
||||
role.grant_scope_ids = [instances.scopes.org.id];
|
||||
await controller.setGrantScopes(role);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, [instances.scopes.org.id]);
|
||||
});
|
||||
|
||||
test('cancel action causes transition to expected route', async function (assert) {
|
||||
test('cancel action rolls back changes causes transition to expected route', async function (assert) {
|
||||
await visit(urls.manageCustomScopes);
|
||||
const role = await store.findRecord('role', instances.role.id);
|
||||
|
||||
await controller.cancel();
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
|
||||
role.grant_scope_ids = [instances.scopes.org.id];
|
||||
await controller.cancel(role);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
assert.strictEqual(currentURL(), urls.manageScopes);
|
||||
});
|
||||
},
|
||||
|
||||
+8
-5
@@ -83,22 +83,25 @@ module(
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
|
||||
await controller.setGrantScopes(role, [instances.scopes.project.id]);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, [instances.scopes.project.id]);
|
||||
|
||||
role.grant_scope_ids = [instances.scopes.project.id];
|
||||
await controller.setGrantScopes(role);
|
||||
await waitUntil(() => currentURL() === urls.manageCustomScopes);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, [instances.scopes.project.id]);
|
||||
assert.strictEqual(currentURL(), urls.manageCustomScopes);
|
||||
});
|
||||
|
||||
test('cancel action causes transition to expected route', async function (assert) {
|
||||
test('cancel action rolls back changes causes transition to expected route', async function (assert) {
|
||||
await visit(urls.manageOrgProjects);
|
||||
const role = await store.findRecord('role', instances.role.id);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
|
||||
role.grant_scope_ids = [instances.scopes.project.id];
|
||||
await controller.cancel(role);
|
||||
await waitUntil(() => currentURL() === urls.manageCustomScopes);
|
||||
|
||||
assert.deepEqual(role.grant_scope_ids, []);
|
||||
assert.strictEqual(currentURL(), urls.manageCustomScopes);
|
||||
});
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user