Icu 13359 refactor query requests for resources added to indexed db (#2224)
* refactor: 💡 update query requests for resources in indexedDB ✅ Closes: https://hashicorp.atlassian.net/browse/ICU-13359
This commit is contained in:
1 parent
5d32d987bc
commit
edba33bbda
15 files changed
+159
-175
No files matched your search
@@ -112,7 +112,7 @@ export default class IndexedDbHandler {
|
||||
);
|
||||
|
||||
const dbRecords = paginateResults(indexedDbResults, page, pageSize).map(
|
||||
this.indexedDb.normalizeData,
|
||||
(item) => this.indexedDb.normalizeData(item, false),
|
||||
);
|
||||
|
||||
// Return the raw data if we don't push to the store.
|
||||
|
||||
@@ -6,17 +6,11 @@
|
||||
import GeneratedRoleModel from '../generated/models/role';
|
||||
import { attr } from '@ember-data/model';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { all, resolve } from 'rsvp';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default class RoleModel extends GeneratedRoleModel {
|
||||
// =services
|
||||
|
||||
@service store;
|
||||
@service resourceFilterStore;
|
||||
|
||||
// =attributes
|
||||
|
||||
@@ -78,91 +72,6 @@ export default class RoleModel extends GeneratedRoleModel {
|
||||
.map(({ id }) => id);
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that resolves to an array of User instances.
|
||||
* When calling this getter, be sure to await resolution
|
||||
* before interacting with the results.
|
||||
* @type {Promise[UserModel]}
|
||||
*/
|
||||
get users() {
|
||||
const ids = this.userIDs;
|
||||
|
||||
// Role has prinicipal IDs,
|
||||
// return a promise which resolves model instances for those IDs
|
||||
if (ids?.length) {
|
||||
return this.resourceFilterStore
|
||||
.queryBy('user', { id: ids }, { scope_id: 'global', recursive: true })
|
||||
.then((models) => models.map((model) => model));
|
||||
}
|
||||
|
||||
// No principal IDs,
|
||||
// return a promise resolving to an empty array
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that resolves to an array of Group instances.
|
||||
* When calling this getter, be sure to await resolution
|
||||
* before interacting with the results.
|
||||
* @type {Promise[GroupModel]}
|
||||
*/
|
||||
get groups() {
|
||||
const ids = this.groupIDs;
|
||||
|
||||
// Role has prinicipal IDs,
|
||||
// return a promise which resolves model instances for those IDs
|
||||
if (ids?.length) {
|
||||
return this.resourceFilterStore
|
||||
.queryBy('group', { id: ids }, { scope_id: 'global', recursive: true })
|
||||
.then((models) => models.map((model) => model));
|
||||
}
|
||||
|
||||
// No principal IDs,
|
||||
// return a promise resolving to an empty array
|
||||
return resolve([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that resolves to an array of ManagedGroup instances.
|
||||
* When calling this getter, be sure to await resolution
|
||||
* before interacting with the results.
|
||||
* @type {Promise[ManagedGroupModel]}
|
||||
*/
|
||||
get managedGroups() {
|
||||
const ids = this.managedGroupIDs;
|
||||
|
||||
// Role has prinicipal IDs
|
||||
// return a promise which resolves model instances for those IDs
|
||||
if (ids?.length) {
|
||||
// Collect all auth methods.
|
||||
const authMethods = this.resourceFilterStore.queryBy(
|
||||
'auth-method',
|
||||
{ type: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
|
||||
{ scope_id: 'global', recursive: true },
|
||||
);
|
||||
|
||||
// For each auth method, query all managed groups with IDs
|
||||
// that match the role's manage group principal IDs.
|
||||
const managedGroups = authMethods
|
||||
.then((methods) =>
|
||||
all(
|
||||
methods.map(({ id: auth_method_id }) =>
|
||||
this.resourceFilterStore
|
||||
.queryBy('managed-group', { id: ids }, { auth_method_id })
|
||||
.then((models) => models.map((model) => model)),
|
||||
),
|
||||
),
|
||||
)
|
||||
// The result is an array of arrays of model instances (grouped by
|
||||
// auth methods), so these must be flattened.
|
||||
.then((grouped) => grouped.flat());
|
||||
return managedGroups;
|
||||
}
|
||||
|
||||
// No principal IDs,
|
||||
// return a promise resolving to an empty array
|
||||
return resolve([]);
|
||||
}
|
||||
// =methods
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,16 +6,15 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { hash } from 'rsvp';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import { resourceFilter } from 'core/decorators/resource-filter';
|
||||
|
||||
export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service store;
|
||||
@service intl;
|
||||
@service router;
|
||||
@service resourceFilterStore;
|
||||
|
||||
// =attributes
|
||||
|
||||
@@ -39,28 +38,25 @@ export default class ScopesScopeGroupsGroupAddMembersRoute extends Route {
|
||||
|
||||
/**
|
||||
* Loads all users and returns them with the group.
|
||||
* @return {Promise{GroupModel, [UserModel]}}
|
||||
* @return {Promise<{group: GroupModel, users: [UserModel], scopes: [ScopeModel] }> }
|
||||
*/
|
||||
model() {
|
||||
async model() {
|
||||
const group = this.modelFor('scopes.scope.groups.group');
|
||||
// filter out projects, since the user resource exists only on org and above
|
||||
const scopes = this.store
|
||||
.peekAll('scope')
|
||||
.filter((scope) => !scope.isProject);
|
||||
const scopeIDs = this.scope?.map((scope) => scope.id);
|
||||
const users = scopeIDs?.length
|
||||
? this.resourceFilterStore.queryBy(
|
||||
'user',
|
||||
{
|
||||
scope_id: scopeIDs,
|
||||
},
|
||||
{
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
},
|
||||
)
|
||||
: this.store.query('user', { scope_id: 'global', recursive: true });
|
||||
return hash({ group, users, scopes });
|
||||
const query = { filters: { scope_id: [] } };
|
||||
scopeIDs?.forEach((scopeID) => {
|
||||
query.filters.scope_id.push({ equals: scopeID });
|
||||
});
|
||||
const users = await this.store.query('user', {
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
query,
|
||||
});
|
||||
return { group, users, scopes };
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
@@ -5,32 +5,40 @@
|
||||
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { hash } from 'rsvp';
|
||||
|
||||
export default class ScopesScopeGroupsGroupMembersRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service intl;
|
||||
|
||||
@service resourceFilterStore;
|
||||
@service store;
|
||||
|
||||
// =methods
|
||||
|
||||
/**
|
||||
* Returns users associated with this group.
|
||||
* @return {Promise{group: GroupModel, members: Promise{[UserModel]}}}
|
||||
* @return {Promise<{group: GroupModel, members: [UserModel]}>}
|
||||
*/
|
||||
model() {
|
||||
async model() {
|
||||
const group = this.modelFor('scopes.scope.groups.group');
|
||||
return hash({
|
||||
group,
|
||||
members: group.member_ids?.length
|
||||
? this.resourceFilterStore.queryBy(
|
||||
'user',
|
||||
{ id: group.member_ids },
|
||||
{ scope_id: 'global', recursive: true },
|
||||
)
|
||||
: [],
|
||||
});
|
||||
const members = await this.getUsers(group.member_ids);
|
||||
return { group, members };
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves group members of user type.
|
||||
* @param {array} ids
|
||||
* @return {Promise[UserModel]}
|
||||
*/
|
||||
async getUsers(ids) {
|
||||
let users = [];
|
||||
if (ids?.length) {
|
||||
const query = { filters: { id: [] } };
|
||||
ids.forEach((id) => query.filters.id.push({ equals: id }));
|
||||
users = await this.store.query('user', {
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
query,
|
||||
});
|
||||
}
|
||||
return users;
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,7 @@ export default class ScopesScopeRolesIndexRoute extends Route {
|
||||
|
||||
/**
|
||||
* Loads queried roles and the number of roles under current scope.
|
||||
* @returns {Promise<{totalItems: number, users: [RoleModel], rolesExist: boolean }> }
|
||||
* @returns {Promise<{totalItems: number, roles: [RoleModel], rolesExist: boolean }> }
|
||||
*/
|
||||
async model({ search, page, pageSize }) {
|
||||
const scope = this.modelFor('scopes.scope');
|
||||
@@ -61,7 +61,7 @@ export default class ScopesScopeRolesIndexRoute extends Route {
|
||||
* Sets rolesExist to true if there exists any roles.
|
||||
* @param {string} scope_id
|
||||
* @param {number} totalItems
|
||||
* @returns
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async getRolesExist(scope_id, totalItems) {
|
||||
if (totalItems > 0) {
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { inject as service } from '@ember/service';
|
||||
import { action } from '@ember/object';
|
||||
import { hash, all } from 'rsvp';
|
||||
import { loading } from 'ember-loading';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import { resourceFilter } from 'core/decorators/resource-filter';
|
||||
@@ -18,7 +17,6 @@ import {
|
||||
export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
// =services
|
||||
|
||||
@service intl;
|
||||
@service router;
|
||||
@service store;
|
||||
@service resourceFilterStore;
|
||||
@@ -51,30 +49,20 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
const role = this.modelFor('scopes.scope.roles.role');
|
||||
const scopes = this.store.peekAll('scope');
|
||||
const scopeIDs = this.scope?.map((scope) => scope.id);
|
||||
const users = scopeIDs?.length
|
||||
? this.resourceFilterStore.queryBy(
|
||||
'user',
|
||||
{
|
||||
scope_id: scopeIDs,
|
||||
},
|
||||
{
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
},
|
||||
)
|
||||
: this.store.query('user', { scope_id: 'global', recursive: true });
|
||||
const groups = scopeIDs?.length
|
||||
? this.resourceFilterStore.queryBy(
|
||||
'group',
|
||||
{
|
||||
scope_id: scopeIDs,
|
||||
},
|
||||
{
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
},
|
||||
)
|
||||
: this.store.query('group', { scope_id: 'global', recursive: true });
|
||||
const query = { filters: { scope_id: [] } };
|
||||
scopeIDs?.forEach((scopeID) => {
|
||||
query.filters.scope_id.push({ equals: scopeID });
|
||||
});
|
||||
const users = await this.store.query('user', {
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
query,
|
||||
});
|
||||
const groups = await this.store.query('group', {
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
query,
|
||||
});
|
||||
//query authmethods from all the scopes
|
||||
const authMethods = scopeIDs?.length
|
||||
? await this.resourceFilterStore.queryBy(
|
||||
@@ -90,24 +78,20 @@ export default class ScopesScopeRolesRoleAddPrincipalsRoute extends Route {
|
||||
{ type: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
|
||||
{ scope_id: 'global', recursive: true },
|
||||
);
|
||||
//extract oidc and ldap authMethod IDs
|
||||
const authMethodIDs = authMethods.map(({ id }) => id);
|
||||
//query all the managed groups for each auth method id
|
||||
const managedGroups = await all(
|
||||
authMethodIDs.map((auth_method_id) =>
|
||||
const managedGroups = await Promise.all(
|
||||
authMethods.map(({ id: auth_method_id }) =>
|
||||
this.store.query('managed-group', { auth_method_id }),
|
||||
),
|
||||
);
|
||||
const managedGroupModels = managedGroups
|
||||
.map((models) => models.map((model) => model))
|
||||
.flat();
|
||||
return hash({
|
||||
|
||||
return {
|
||||
role,
|
||||
scopes,
|
||||
users,
|
||||
groups,
|
||||
managedGroups: managedGroupModels,
|
||||
});
|
||||
managedGroups: managedGroups.flat(),
|
||||
};
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
@@ -9,10 +9,15 @@ import { inject as service } from '@ember/service';
|
||||
import { loading } from 'ember-loading';
|
||||
import { confirm } from 'core/decorators/confirm';
|
||||
import { notifySuccess, notifyError } from 'core/decorators/notify';
|
||||
import {
|
||||
TYPE_AUTH_METHOD_OIDC,
|
||||
TYPE_AUTH_METHOD_LDAP,
|
||||
} from 'api/models/auth-method';
|
||||
|
||||
export default class ScopesScopeRolesRolePrincipalsRoute extends Route {
|
||||
// =services
|
||||
@service intl;
|
||||
|
||||
@service store;
|
||||
@service resourceFilterStore;
|
||||
|
||||
// =methods
|
||||
@@ -24,16 +29,91 @@ export default class ScopesScopeRolesRolePrincipalsRoute extends Route {
|
||||
*/
|
||||
async model() {
|
||||
const role = this.modelFor('scopes.scope.roles.role');
|
||||
// Fetch user and group principals.
|
||||
const users = await role.users;
|
||||
const groups = await role.groups;
|
||||
const managedGroups = await role.managedGroups;
|
||||
// Fetch user principals.
|
||||
const users = await this.getUsers(role.userIDs);
|
||||
|
||||
// Fetch group principals.
|
||||
const groups = await this.getGroups(role.groupIDs);
|
||||
|
||||
// Fetch managedGroup principals.
|
||||
const managedGroups = await this.getManagedGroups(role.managedGroupIDs);
|
||||
|
||||
// Merge polymorphic principals.
|
||||
const principals = [...users, ...groups, ...managedGroups];
|
||||
|
||||
return { role, principals };
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves role principals of user type.
|
||||
* @param {array} ids
|
||||
* @return {Promise[UserModel]}
|
||||
*/
|
||||
async getUsers(ids) {
|
||||
let users = [];
|
||||
if (ids?.length) {
|
||||
const query = { filters: { id: [] } };
|
||||
ids.forEach((id) => query.filters.id.push({ equals: id }));
|
||||
users = await this.store.query('user', {
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
query,
|
||||
});
|
||||
}
|
||||
return users;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves role principals of group type.
|
||||
* @param {array} ids
|
||||
* @return {Promise[GroupModel]}
|
||||
*/
|
||||
async getGroups(ids) {
|
||||
let groups = [];
|
||||
if (ids?.length) {
|
||||
const query = { filters: { id: [] } };
|
||||
ids.forEach((id) => query.filters.id.push({ equals: id }));
|
||||
groups = await this.store.query('group', {
|
||||
scope_id: 'global',
|
||||
recursive: true,
|
||||
query,
|
||||
});
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves role principals of managed-group type.
|
||||
* @param {array} ids
|
||||
* @return {Promise[ManagedGroupModel]}
|
||||
*/
|
||||
async getManagedGroups(ids) {
|
||||
let managedGroups = [];
|
||||
if (ids?.length) {
|
||||
// TODO: Refactor to directly use store service
|
||||
// when types get added to indexedDB.
|
||||
|
||||
// Collect all oidc and ldap type auth methods.
|
||||
const authMethods = await this.resourceFilterStore.queryBy(
|
||||
'auth-method',
|
||||
{ type: [TYPE_AUTH_METHOD_OIDC, TYPE_AUTH_METHOD_LDAP] },
|
||||
{ scope_id: 'global', recursive: true },
|
||||
);
|
||||
|
||||
const nestedManagedGroups = await Promise.all(
|
||||
authMethods.map(({ id: auth_method_id }) =>
|
||||
this.resourceFilterStore.queryBy(
|
||||
'managed-group',
|
||||
{ id: ids },
|
||||
{ auth_method_id },
|
||||
),
|
||||
),
|
||||
);
|
||||
managedGroups = nestedManagedGroups.flat();
|
||||
}
|
||||
return managedGroups;
|
||||
}
|
||||
|
||||
// =actions
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,7 +62,7 @@ export default class ScopesScopeUsersIndexRoute extends Route {
|
||||
* Sets usersExist to true if there exists any users.
|
||||
* @param {string} scope_id
|
||||
* @param {number} totalItems
|
||||
* @returns
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async getUsersExist(scope_id, totalItems) {
|
||||
if (totalItems > 0) {
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
@text={{t
|
||||
'descriptions.no-search-results'
|
||||
query=this.search
|
||||
resource='roles'
|
||||
resource=(t 'resources.role.title_plural')
|
||||
}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
'descriptions.no-filter-results'
|
||||
)
|
||||
query=this.search
|
||||
resource='targets'
|
||||
resource=(t 'resources.target.title_plural')
|
||||
}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
@text={{t
|
||||
'descriptions.no-search-results'
|
||||
query=this.search
|
||||
resource='users'
|
||||
resource=(t 'resources.user.title_plural')
|
||||
}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { module, test } from 'qunit';
|
||||
import { visit, currentURL, click, find, findAll } from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { Response } from 'miragejs';
|
||||
import {
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
module('Acceptance | groups | members', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
setupIndexedDb(hooks);
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { module, test } from 'qunit';
|
||||
import { visit, currentURL, click, find, findAll } from '@ember/test-helpers';
|
||||
import { setupApplicationTest } from 'ember-qunit';
|
||||
import setupMirage from 'ember-cli-mirage/test-support/setup-mirage';
|
||||
import { setupIndexedDb } from 'api/test-support/helpers/indexed-db';
|
||||
import a11yAudit from 'ember-a11y-testing/test-support/audit';
|
||||
import { Response } from 'miragejs';
|
||||
import {
|
||||
@@ -19,6 +20,7 @@ import {
|
||||
module('Acceptance | roles | principals', function (hooks) {
|
||||
setupApplicationTest(hooks);
|
||||
setupMirage(hooks);
|
||||
setupIndexedDb(hooks);
|
||||
|
||||
const instances = {
|
||||
scopes: {
|
||||
|
||||
@@ -158,7 +158,10 @@
|
||||
<Hds::ApplicationState data-test-no-session-results as |A|>
|
||||
<A.Header @title={{t 'titles.no-results-found'}} />
|
||||
<A.Body
|
||||
@text={{t 'descriptions.no-filter-results' resource='sessions'}}
|
||||
@text={{t
|
||||
'descriptions.no-filter-results'
|
||||
resource=(t 'resources.session.title_plural')
|
||||
}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
{{/if}}
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
'descriptions.no-filter-results'
|
||||
)
|
||||
query=this.search
|
||||
resource='targets'
|
||||
resource=(t 'resources.target.title_plural')
|
||||
}}
|
||||
/>
|
||||
</Hds::ApplicationState>
|
||||
|
||||
Reference in new issue
Block a user