Fix Searchbar debouncing in admin UI (#2735)

Applied ember-concurrency task usage to admin UI model hooks to help fix the debouncing issue.
This commit is contained in:
Zhihe Li authored and GitHub committed 2025-03-18 11:20:50 -04:00
1 parent 01c34c0a79
commit f8b3792e62
28 files changed
+689 -519

No files matched your search

@@ -8,7 +8,6 @@ import { service } from '@ember/service';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { loading } from 'ember-loading';
import { debounce } from 'core/decorators/debounce';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { confirm } from 'core/decorators/confirm';
@@ -120,7 +119,6 @@ export default class ScopesScopeAliasesIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -10,7 +10,6 @@ import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { tracked } from '@glimmer/tracking';
import { debounce } from 'core/decorators/debounce';
import { TYPES_AUTH_METHOD } from 'api/models/auth-method';
export default class ScopesScopeAuthMethodsIndexController extends Controller {
@@ -104,7 +103,6 @@ export default class ScopesScopeAuthMethodsIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -9,7 +9,6 @@ import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { debounce } from 'core/decorators/debounce';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { TYPES_CREDENTIAL_STORE } from 'api/models/credential-store';
@@ -133,7 +132,6 @@ export default class ScopesScopeCredentialStoresIndexController extends Controll
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -10,7 +10,6 @@ import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { debounce } from 'core/decorators/debounce';
export default class ScopesScopeGroupsIndexController extends Controller {
// =services
@@ -23,7 +22,7 @@ export default class ScopesScopeGroupsIndexController extends Controller {
queryParams = ['search', 'page', 'pageSize'];
@tracked search = '';
@tracked search;
@tracked page = 1;
@tracked pageSize = 10;
@@ -120,7 +119,6 @@ export default class ScopesScopeGroupsIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -7,7 +7,6 @@ import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { debounce } from 'core/decorators/debounce';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
@@ -60,7 +59,6 @@ export default class ScopesScopeHostCatalogsIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -8,7 +8,6 @@ import { service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { tracked } from '@glimmer/tracking';
import { debounce } from 'core/decorators/debounce';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
import { GRANT_SCOPE_THIS } from 'api/models/role';
@@ -24,7 +23,7 @@ export default class ScopesScopeRolesIndexController extends Controller {
queryParams = ['search', 'page', 'pageSize'];
@tracked search = '';
@tracked search;
@tracked page = 1;
@tracked pageSize = 10;
@@ -62,7 +61,6 @@ export default class ScopesScopeRolesIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -8,7 +8,6 @@ import { service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { tracked } from '@glimmer/tracking';
import { debounce } from 'core/decorators/debounce';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesRoleManageScopesManageCustomScopesController extends Controller {
@@ -22,7 +21,7 @@ export default class ScopesScopeRolesRoleManageScopesManageCustomScopesControlle
queryParams = ['search', 'page', 'pageSize'];
@tracked search = '';
@tracked search;
@tracked page = 1;
@tracked pageSize = 10;
@@ -33,7 +32,6 @@ export default class ScopesScopeRolesRoleManageScopesManageCustomScopesControlle
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -8,7 +8,6 @@ import { service } from '@ember/service';
import { action } from '@ember/object';
import { loading } from 'ember-loading';
import { tracked } from '@glimmer/tracking';
import { debounce } from 'core/decorators/debounce';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsController extends Controller {
@@ -22,7 +21,7 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsController
queryParams = ['search', 'page', 'pageSize'];
@tracked search = '';
@tracked search;
@tracked page = 1;
@tracked pageSize = 10;
@@ -33,7 +32,6 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsController
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -7,7 +7,6 @@ import Controller, { inject as controller } from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { debounce } from 'core/decorators/debounce';
import {
GRANT_SCOPE_THIS,
GRANT_SCOPE_CHILDREN,
@@ -32,7 +31,7 @@ export default class ScopesScopeRolesRoleScopesController extends Controller {
'pageSize',
];
@tracked search = '';
@tracked search;
@tracked parentScopes = [];
@tracked types = [];
@tracked page = 1;
@@ -108,7 +107,6 @@ export default class ScopesScopeRolesRoleScopesController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -6,14 +6,13 @@
import Controller from '@ember/controller';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
import { debounce } from 'core/decorators/debounce';
export default class ScopesScopeScopesIndexController extends Controller {
// =attributes
queryParams = ['search', 'page', 'pageSize'];
@tracked search = '';
@tracked search;
@tracked page = 1;
@tracked pageSize = 10;
@@ -24,7 +23,6 @@ export default class ScopesScopeScopesIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -6,7 +6,6 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { debounce } from 'core/decorators/debounce';
import { service } from '@ember/service';
export default class ScopesScopeSessionRecordingsIndexController extends Controller {
@@ -29,7 +28,7 @@ export default class ScopesScopeSessionRecordingsIndexController extends Control
now = new Date();
@tracked search = '';
@tracked search;
@tracked time = null;
@tracked users = [];
@tracked scopes = [];
@@ -155,7 +154,6 @@ export default class ScopesScopeSessionRecordingsIndexController extends Control
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -13,7 +13,6 @@ import {
statusTypes,
} from 'api/models/session';
import { action } from '@ember/object';
import { debounce } from 'core/decorators/debounce';
import { notifySuccess, notifyError } from 'core/decorators/notify';
export default class ScopesScopeSessionsIndexController extends Controller {
@@ -33,7 +32,7 @@ export default class ScopesScopeSessionsIndexController extends Controller {
'pageSize',
];
@tracked search = '';
@tracked search;
@tracked users = [];
@tracked targets = [];
@tracked status = [
@@ -81,7 +80,6 @@ export default class ScopesScopeSessionsIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -7,7 +7,6 @@ import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { debounce } from 'core/decorators/debounce';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
@@ -104,7 +103,6 @@ export default class ScopesScopeTargetsIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -7,7 +7,6 @@ import Controller from '@ember/controller';
import { service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { debounce } from 'core/decorators/debounce';
import { loading } from 'ember-loading';
import { confirm } from 'core/decorators/confirm';
import { notifySuccess, notifyError } from 'core/decorators/notify';
@@ -23,7 +22,7 @@ export default class ScopesScopeUsersIndexController extends Controller {
queryParams = ['search', 'page', 'pageSize'];
@tracked search = '';
@tracked search;
@tracked page = 1;
@tracked pageSize = 10;
@@ -59,7 +58,6 @@ export default class ScopesScopeUsersIndexController extends Controller {
* @param {object} event
*/
@action
@debounce(250)
handleSearchInput(event) {
const { value } = event.target;
this.search = value;
@@ -6,6 +6,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { hash } from 'rsvp';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeAliasesIndexRoute extends Route {
// =services
@@ -34,46 +35,58 @@ export default class ScopesScopeAliasesIndexRoute extends Route {
* Loads queried aliases and the number of aliases under current scope.
* @returns {Promise<{totalItems: number, aliases: [object], aliasesExist: boolean}>}
*/
async model({ search, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
let aliases;
let doAliasesExist = false;
let totalItems = 0;
if (
this.can.can('list model', scope, {
collection: 'aliases',
})
) {
aliases = await this.store.query('alias', {
scope_id,
query: { search },
page,
pageSize,
});
totalItems = aliases.meta?.totalItems;
// since we don't receive target info from aliases list API,
// we query the store to fetch target information based on the destination id
aliases = await Promise.all(
aliases.map((alias) =>
hash({
alias,
target: alias.destination_id
? this.store.findRecord('target', alias.destination_id, {
backgroundReload: false,
})
: null,
}),
),
);
doAliasesExist = await this.getDoAliasesExist(scope_id, totalItems);
}
return { aliases, doAliasesExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
let aliases;
let doAliasesExist = false;
let totalItems = 0;
if (
this.can.can('list model', scope, {
collection: 'aliases',
})
) {
aliases = await this.store.query('alias', {
scope_id,
query: { search },
page,
pageSize,
});
totalItems = aliases.meta?.totalItems;
// since we don't receive target info from aliases list API,
// we query the store to fetch target information based on the destination id
aliases = await Promise.all(
aliases.map((alias) =>
hash({
alias,
target: alias.destination_id
? this.store.findRecord('target', alias.destination_id, {
backgroundReload: false,
})
: null,
}),
),
);
doAliasesExist = await this.getDoAliasesExist(scope_id, totalItems);
}
return { aliases, doAliasesExist, totalItems };
},
);
/**
* Sets doAliasesExist to true if there are any aliases.
* @param {string} scope_id
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeAuthMethodsIndexRoute extends Route {
// =services
@@ -42,50 +43,62 @@ export default class ScopesScopeAuthMethodsIndexRoute extends Route {
* Loads queried auth-methods and the number of auth-methods under current scope.
* @returns {Promise<{totalItems: number, authMethods: [AuthMethodModel], doAuthMethodsExist: boolean }> }
*/
async model({ search, types, primary, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
type: [],
is_primary: [],
};
types.forEach((type) => {
filters.type.push({ equals: type });
});
if (primary.length == 1) {
primary.forEach((val) => {
filters.is_primary.push({ equals: val });
});
}
let authMethods;
let totalItems = 0;
let doAuthMethodsExist = false;
if (this.can.can('list model', scope, { collection: 'auth-methods' })) {
// TODO: Remove storeToken option as this is a temporary fix for auth-methods.
const options = { storeToken: false };
authMethods = await this.store.query(
'auth-method',
{
scope_id,
query: { search, filters },
page,
pageSize,
},
options,
);
totalItems = authMethods.meta?.totalItems;
doAuthMethodsExist = await this.getDoAuthMethodsExist(
scope_id,
totalItems,
);
}
return { authMethods, doAuthMethodsExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, types, primary, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
type: [],
is_primary: [],
};
types.forEach((type) => {
filters.type.push({ equals: type });
});
if (primary.length === 1) {
primary.forEach((val) => {
filters.is_primary.push({ equals: val });
});
}
let authMethods;
let totalItems = 0;
let doAuthMethodsExist = false;
if (this.can.can('list model', scope, { collection: 'auth-methods' })) {
// TODO: Remove storeToken option as this is a temporary fix for auth-methods.
const options = { storeToken: false };
authMethods = await this.store.query(
'auth-method',
{
scope_id,
query: { search, filters },
page,
pageSize,
},
options,
);
totalItems = authMethods.meta?.totalItems;
doAuthMethodsExist = await this.getDoAuthMethodsExist(
scope_id,
totalItems,
);
}
return { authMethods, doAuthMethodsExist, totalItems };
},
);
/**
* Sets doAuthMethodsExist to true if there exists any auth methods.
* @param {string} scope_id
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeCredentialStoresIndexRoute extends Route {
// =services
@@ -37,41 +38,53 @@ export default class ScopesScopeCredentialStoresIndexRoute extends Route {
* Loads queried credential-stores and the number of credential-stores under current scope.
* @returns {Promise<{totalItems: number, credentialStores: [CredentialStoreModel], doCredentialStoresExist: boolean }> }
*/
async model({ search, types, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
type: [],
};
types.forEach((type) => {
filters.type.push({ equals: type });
});
let credentialStores;
let totalItems = 0;
let doCredentialStoresExist = false;
if (
this.can.can('list model', scope, {
collection: 'credential-stores',
})
) {
credentialStores = await this.store.query('credential-store', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = credentialStores.meta?.totalItems;
doCredentialStoresExist = await this.getDoCredentialStoresExist(
scope_id,
totalItems,
);
}
return { credentialStores, doCredentialStoresExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, types, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
type: [],
};
types.forEach((type) => {
filters.type.push({ equals: type });
});
let credentialStores;
let totalItems = 0;
let doCredentialStoresExist = false;
if (
this.can.can('list model', scope, {
collection: 'credential-stores',
})
) {
credentialStores = await this.store.query('credential-store', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = credentialStores.meta?.totalItems;
doCredentialStoresExist = await this.getDoCredentialStoresExist(
scope_id,
totalItems,
);
}
return { credentialStores, doCredentialStoresExist, totalItems };
},
);
/**
* Sets doCredentialStoresExist to true if there exists any credential-stores.
* @param {string} scope_id
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeGroupsIndexRoute extends Route {
// =services
@@ -33,28 +34,40 @@ export default class ScopesScopeGroupsIndexRoute extends Route {
* Loads queried groups and the number of groups under current scope.
* @returns {Promise<{totalItems: number, groups: [GroupModel], doGroupsExist: boolean }> }
*/
async model({ search, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
let groups = [];
let totalItems = 0;
let doGroupsExist = false;
const filters = { scope_id: [{ equals: scope_id }] };
if (this.can.can('list model', scope, { collection: 'groups' })) {
groups = await this.store.query('group', {
scope_id,
query: { filters, search },
page,
pageSize,
});
totalItems = groups.meta?.totalItems;
doGroupsExist = await this.getDoGroupsExist(scope_id, totalItems);
}
return { groups, doGroupsExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
let groups = [];
let totalItems = 0;
let doGroupsExist = false;
const filters = { scope_id: [{ equals: scope_id }] };
if (this.can.can('list model', scope, { collection: 'groups' })) {
groups = await this.store.query('group', {
scope_id,
query: { filters, search },
page,
pageSize,
});
totalItems = groups.meta?.totalItems;
doGroupsExist = await this.getDoGroupsExist(scope_id, totalItems);
}
return { groups, doGroupsExist, totalItems };
},
);
/**
* Sets doGroupsExist to true if there exists any groups.
* @param {string} scope_id
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeHostCatalogsIndexRoute extends Route {
// =services
@@ -33,36 +34,48 @@ export default class ScopesScopeHostCatalogsIndexRoute extends Route {
* Loads all host catalogs under the current scope.
* @returns {Promise<{doHostCatalogsExist: boolean, totalItems: number, hostCatalogs: [HostCatalogModel]}>}
*/
async model({ search, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
type: [],
'plugin.name': [],
};
let hostCatalogs;
let totalItems = 0;
let doHostCatalogsExist = false;
if (this.can.can('list model', scope, { collection: 'host-catalogs' })) {
hostCatalogs = await this.store.query('host-catalog', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = hostCatalogs.meta?.totalItems;
doHostCatalogsExist = await this.getDoHostCatalogsExist(
scope_id,
totalItems,
);
}
return { hostCatalogs, totalItems, doHostCatalogsExist };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
type: [],
'plugin.name': [],
};
let hostCatalogs;
let totalItems = 0;
let doHostCatalogsExist = false;
if (this.can.can('list model', scope, { collection: 'host-catalogs' })) {
hostCatalogs = await this.store.query('host-catalog', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = hostCatalogs.meta?.totalItems;
doHostCatalogsExist = await this.getDoHostCatalogsExist(
scope_id,
totalItems,
);
}
return { hostCatalogs, totalItems, doHostCatalogsExist };
},
);
/**
* Returns true if any host catalogs exist.
* @param {string} scope_id
+35 -22
View File
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeRolesIndexRoute extends Route {
// =attributes
@@ -33,30 +34,42 @@ export default class ScopesScopeRolesIndexRoute extends Route {
* Loads queried roles and the number of roles under current scope.
* @returns {Promise<{totalItems: number, roles: [RoleModel], doRolesExist: boolean }> }
*/
async model({ search, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
};
let roles;
let totalItems = 0;
let doRolesExist = false;
if (this.can.can('list model', scope, { collection: 'roles' })) {
roles = await this.store.query('role', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = roles.meta?.totalItems;
doRolesExist = await this.getDoRolesExist(scope_id, totalItems);
}
return { roles, doRolesExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
};
let roles;
let totalItems = 0;
let doRolesExist = false;
if (this.can.can('list model', scope, { collection: 'roles' })) {
roles = await this.store.query('role', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = roles.meta?.totalItems;
doRolesExist = await this.getDoRolesExist(scope_id, totalItems);
}
return { roles, doRolesExist, totalItems };
},
);
/**
* Sets doRolesExist to true if there exists any roles.
* @param {string} scope_id
@@ -8,6 +8,7 @@ import { action } from '@ember/object';
import { service } from '@ember/service';
import { TrackedObject } from 'tracked-built-ins';
import { TYPE_SCOPE_PROJECT } from 'api/models/scope';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeRolesRoleManageScopesManageCustomScopesRoute extends Route {
// =attributes
@@ -37,41 +38,53 @@ export default class ScopesScopeRolesRoleManageScopesManageCustomScopesRoute ext
* Loads sub scopes for the current scope.
* @returns {Promise<{role: RoleModel, orgScopes: [ScopeModel], projectTotals: object, totalItems: number, totalItemsCount: number}> }
*/
async model({ search, page, pageSize }) {
const role = this.modelFor('scopes.scope.roles.role');
const currentScope = this.modelFor('scopes.scope');
const { id: scope_id } = currentScope;
const filters = {
scope_id: [{ equals: scope_id }],
};
const orgScopes = await this.store.query('scope', {
scope_id,
query: { search, filters },
page,
pageSize,
recursive: true,
});
const totalItems = orgScopes.meta?.totalItems;
const totalItemsCount = await this.getTotalItemsCount(
scope_id,
search,
totalItems,
);
const projectTotals = await this.getProjectTotals(
role.grantScopeProjectIDs,
);
return {
role,
orgScopes,
projectTotals,
totalItems,
totalItemsCount,
};
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const role = this.modelFor('scopes.scope.roles.role');
const currentScope = this.modelFor('scopes.scope');
const { id: scope_id } = currentScope;
const filters = {
scope_id: [{ equals: scope_id }],
};
const orgScopes = await this.store.query('scope', {
scope_id,
query: { search, filters },
page,
pageSize,
recursive: true,
});
const totalItems = orgScopes.meta?.totalItems;
const totalItemsCount = await this.getTotalItemsCount(
scope_id,
search,
totalItems,
);
const projectTotals = await this.getProjectTotals(
role.grantScopeProjectIDs,
);
return {
role,
orgScopes,
projectTotals,
totalItems,
totalItemsCount,
};
},
);
/**
* Creates an object that contains the number of selected projects
* and the total number of projects for each org scope.
@@ -6,6 +6,7 @@
import Route from '@ember/routing/route';
import { action } from '@ember/object';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute extends Route {
// =attributes
@@ -35,39 +36,51 @@ export default class ScopesScopeRolesRoleManageScopesManageOrgProjectsRoute exte
* Loads projects for current org scope.
* @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');
const orgScope = this.store.peekRecord('scope', org_id);
const filters = {
scope_id: [{ equals: org_id }],
};
const projectScopes = await this.store.query('scope', {
scope_id: role.scope.id,
query: { search, filters },
page,
pageSize,
recursive: true,
});
const totalItems = projectScopes.meta?.totalItems;
const totalItemsCount = await this.getTotalItemsCount(
org_id,
search,
totalItems,
);
const remainingProjectIDs = await this.getRemainingProjects(role, org_id);
return {
role,
orgScope,
projectScopes,
totalItems,
totalItemsCount,
remainingProjectIDs,
};
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ org_id, search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const role = this.modelFor('scopes.scope.roles.role');
const orgScope = this.store.peekRecord('scope', org_id);
const filters = {
scope_id: [{ equals: org_id }],
};
const projectScopes = await this.store.query('scope', {
scope_id: role.scope.id,
query: { search, filters },
page,
pageSize,
recursive: true,
});
const totalItems = projectScopes.meta?.totalItems;
const totalItemsCount = await this.getTotalItemsCount(
org_id,
search,
totalItems,
);
const remainingProjectIDs = await this.getRemainingProjects(role, org_id);
return {
role,
orgScope,
projectScopes,
totalItems,
totalItemsCount,
remainingProjectIDs,
};
},
);
/**
* Sets scopesExist to true if there exists any scopes and
* sets totalItemsCount to the number of scopes that exist.
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeRolesRoleScopesRoute extends Route {
// =services
@@ -40,49 +41,61 @@ export default class ScopesScopeRolesRoleScopesRoute extends Route {
* Loads grant scopes for current role.
* @return {Promise<{role: RoleModel, grantScopes: [ScopeModel], allGrantScopes: [ScopeModel], totalItems: number}> }
*/
async model({ search, parentScopes, types, page, pageSize }) {
const role = this.modelFor('scopes.scope.roles.role');
const filters = {
scope_id: [],
type: [],
id: [],
};
role.grant_scope_ids.forEach((id) => {
if (id.startsWith('p_') || id.startsWith('o_')) {
filters.id.push({ equals: id });
}
});
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
let grantScopes = [];
if (!parentScopes.length && !types.length) {
role.grantScopeKeywords.forEach((keyword) => {
if (keyword.includes(search)) {
grantScopes.push({ id: keyword });
retrieveData = restartableTask(
async ({ search, parentScopes, types, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const role = this.modelFor('scopes.scope.roles.role');
const filters = {
scope_id: [],
type: [],
id: [],
};
role.grant_scope_ids.forEach((id) => {
if (id.startsWith('p_') || id.startsWith('o_')) {
filters.id.push({ equals: id });
}
});
}
let allGrantScopes = [];
let totalItems = grantScopes.length;
if (filters.id.length) {
parentScopes.forEach((id) => filters.scope_id.push({ equals: id }));
types.forEach((type) => filters.type.push({ equals: type }));
let grantScopes = [];
if (!parentScopes.length && !types.length) {
role.grantScopeKeywords.forEach((keyword) => {
if (keyword.includes(search) || !search) {
grantScopes.push({ id: keyword });
}
});
}
allGrantScopes = await this.getAllGrantScopes(filters.id);
let allGrantScopes = [];
let totalItems = grantScopes.length;
if (filters.id.length) {
parentScopes.forEach((id) => filters.scope_id.push({ equals: id }));
types.forEach((type) => filters.type.push({ equals: type }));
const queriedScopes = await this.store.query('scope', {
scope_id: role.scope.id,
query: { search, filters },
page,
pageSize: pageSize - totalItems,
recursive: true,
});
grantScopes =
page === 1 ? [...grantScopes, ...queriedScopes] : queriedScopes;
totalItems += queriedScopes.meta?.totalItems;
}
return { role, grantScopes, allGrantScopes, totalItems };
}
allGrantScopes = await this.getAllGrantScopes(filters.id);
const queriedScopes = await this.store.query('scope', {
scope_id: role.scope.id,
query: { search, filters },
page,
pageSize: pageSize - totalItems,
recursive: true,
});
grantScopes =
page === 1 ? [...grantScopes, ...queriedScopes] : queriedScopes;
totalItems += queriedScopes.meta?.totalItems;
}
return { role, grantScopes, allGrantScopes, totalItems };
},
);
/**
* Get all the grant scopes but only load them once when entering the route.
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeScopesIndexRoute extends Route {
// =attributes
@@ -33,30 +34,42 @@ export default class ScopesScopeScopesIndexRoute extends Route {
* Loads sub scopes for the current scope.
* @returns {Promise<{totalItems: number, currentScope: ScopeModel, subScopes: [ScopeModel], doScopesExist: boolean }> }
*/
async model({ search, page, pageSize }) {
const currentScope = this.modelFor('scopes.scope');
const { id: scope_id } = currentScope;
const filters = {
scope_id: [{ equals: scope_id }],
};
const subScopes = await this.store.query('scope', {
scope_id,
query: { search, filters },
page,
pageSize,
});
const totalItems = subScopes.meta?.totalItems;
const doScopesExist = await this.getDoScopesExist(scope_id, totalItems);
return {
currentScope,
subScopes,
doScopesExist,
totalItems,
};
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const currentScope = this.modelFor('scopes.scope');
const { id: scope_id } = currentScope;
const filters = {
scope_id: [{ equals: scope_id }],
};
const subScopes = await this.store.query('scope', {
scope_id,
query: { search, filters },
page,
pageSize,
});
const totalItems = subScopes.meta?.totalItems;
const doScopesExist = await this.getDoScopesExist(scope_id, totalItems);
return {
currentScope,
subScopes,
doScopesExist,
totalItems,
};
},
);
/**
* Sets doScopesExist to true if there exists any scopes.
* @param {string} scope_id
@@ -6,6 +6,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { action } from '@ember/object';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeSessionRecordingsIndexRoute extends Route {
// =services
@@ -50,68 +51,89 @@ export default class ScopesScopeSessionRecordingsIndexRoute extends Route {
* Load all session recordings.
* @return {Promise<{ totalItems: number, sessionRecordings: [SessionRecordingModel], doSessionRecordingsExist: boolean, doStorageBucketsExist: boolean }>}
*/
async model({ search, time, users, scopes, targets, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
let sessionRecordings;
let totalItems = 0;
let doSessionRecordingsExist = false;
let doStorageBucketsExist = false;
const filters = {
created_time: [],
'create_time_values.user.id': [],
'create_time_values.target.scope.id': [],
'create_time_values.target.id': [],
};
if (time) filters.created_time.push({ gte: new Date(time) });
users.forEach((user) => {
filters['create_time_values.user.id'].push({ equals: user });
});
scopes.forEach((scope) => {
filters['create_time_values.target.scope.id'].push({ equals: scope });
});
targets.forEach((target) => {
filters['create_time_values.target.id'].push({ equals: target });
});
if (
this.can.can('list scope', scope, {
collection: 'session-recordings',
})
) {
const queryOptions = {
scope_id,
recursive: true,
query: { search, filters },
page,
pageSize,
};
sessionRecordings = await this.store.query(
'session-recording',
queryOptions,
);
totalItems = sessionRecordings.meta?.totalItems;
// Query all session recordings for filtering values if entering route for the first time
if (!this.allSessionRecordings) {
await this.getAllSessionRecordings(scope_id);
}
doSessionRecordingsExist = await this.getDoSessionRecordingsExist(
scope_id,
totalItems,
);
doStorageBucketsExist = await this.getDoStorageBucketsExist(scope_id);
return {
sessionRecordings,
doSessionRecordingsExist: doSessionRecordingsExist,
allSessionRecordings: this.allSessionRecordings,
totalItems,
doStorageBucketsExist: doStorageBucketsExist,
};
}
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({
search,
time,
users,
scopes,
targets,
page,
pageSize,
useDebounce,
}) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
let sessionRecordings;
let totalItems = 0;
let doSessionRecordingsExist = false;
let doStorageBucketsExist = false;
const filters = {
created_time: [],
'create_time_values.user.id': [],
'create_time_values.target.scope.id': [],
'create_time_values.target.id': [],
};
if (time) filters.created_time.push({ gte: new Date(time) });
users.forEach((user) => {
filters['create_time_values.user.id'].push({ equals: user });
});
scopes.forEach((scope) => {
filters['create_time_values.target.scope.id'].push({ equals: scope });
});
targets.forEach((target) => {
filters['create_time_values.target.id'].push({ equals: target });
});
if (
this.can.can('list scope', scope, {
collection: 'session-recordings',
})
) {
const queryOptions = {
scope_id,
recursive: true,
query: { search, filters },
page,
pageSize,
};
sessionRecordings = await this.store.query(
'session-recording',
queryOptions,
);
totalItems = sessionRecordings.meta?.totalItems;
// Query all session recordings for filtering values if entering route for the first time
if (!this.allSessionRecordings) {
await this.getAllSessionRecordings(scope_id);
}
doSessionRecordingsExist = await this.getDoSessionRecordingsExist(
scope_id,
totalItems,
);
doStorageBucketsExist = await this.getDoStorageBucketsExist(scope_id);
return {
sessionRecordings,
doSessionRecordingsExist: doSessionRecordingsExist,
allSessionRecordings: this.allSessionRecordings,
totalItems,
doStorageBucketsExist: doStorageBucketsExist,
};
}
},
);
/**
* Sets allSessionRecordings to all session recordings for filters
* @param {string} scope_id
@@ -6,6 +6,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { action } from '@ember/object';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeSessionsIndexRoute extends Route {
// =services
@@ -51,57 +52,69 @@ export default class ScopesScopeSessionsIndexRoute extends Route {
* an array of objects containing their associated users and targets.
* @return {Promise{[{sessions: [SessionModel], allSessions: [SessionModel], associatedUsers: [UserModel], associatedTargets: [TargetModel], totalItems: number}]}}
*/
async model({ search, users, targets, status, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
status: [],
user_id: [],
target_id: [],
};
users.forEach((user) => {
filters.user_id.push({ equals: user });
});
targets.forEach((target) => {
filters.target_id.push({ equals: target });
});
status.forEach((item) => {
filters.status.push({ equals: item });
});
const queryOptions = {
scope_id,
include_terminated: true,
query: { search, filters },
page,
pageSize,
};
const sessions = await this.store.query('session', queryOptions);
const totalItems = sessions.meta?.totalItems;
// Query all sessions, users, and targets for defining filtering values if entering route for the first time
if (!this.allSessions) {
await this.getAllSessions(scope_id);
}
if (this.associatedUsers.length === 0) {
await this.getAssociatedUsers(scope);
}
if (this.associatedTargets.length === 0) {
await this.getAssociatedTargets(scope);
}
return {
sessions,
allSessions: this.allSessions,
associatedUsers: this.associatedUsers,
associatedTargets: this.associatedTargets,
totalItems,
};
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, users, targets, status, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
status: [],
user_id: [],
target_id: [],
};
users.forEach((user) => {
filters.user_id.push({ equals: user });
});
targets.forEach((target) => {
filters.target_id.push({ equals: target });
});
status.forEach((item) => {
filters.status.push({ equals: item });
});
const queryOptions = {
scope_id,
include_terminated: true,
query: { search, filters },
page,
pageSize,
};
const sessions = await this.store.query('session', queryOptions);
const totalItems = sessions.meta?.totalItems;
// Query all sessions, users, and targets for defining filtering values if entering route for the first time
if (!this.allSessions) {
await this.getAllSessions(scope_id);
}
if (this.associatedUsers.length === 0) {
await this.getAssociatedUsers(scope);
}
if (this.associatedTargets.length === 0) {
await this.getAssociatedTargets(scope);
}
return {
sessions,
allSessions: this.allSessions,
associatedUsers: this.associatedUsers,
associatedTargets: this.associatedTargets,
totalItems,
};
},
);
/**
* Get all the sessions but only load them once when entering the route.
* @param scope_id
@@ -9,6 +9,7 @@ import {
STATUS_SESSION_ACTIVE,
STATUS_SESSION_PENDING,
} from 'api/models/session';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeTargetsIndexRoute extends Route {
// =services
@@ -47,52 +48,71 @@ export default class ScopesScopeTargetsIndexRoute extends Route {
* active sessions filtering options.
* @returns {Promise<{totalItems: number, targets: [TargetModel], doTargetsExist: boolean }> }
*/
async model({ search, availableSessions, types, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
id: { values: [] },
type: [],
};
types.forEach((type) => {
filters.type.push({ equals: type });
});
if (this.can.can('list model', scope, { collection: 'sessions' })) {
const sessions = await this.store.query('session', {
scope_id,
query: {
filters: {
scope_id: [{ equals: scope_id }],
status: [
{ equals: STATUS_SESSION_ACTIVE },
{ equals: STATUS_SESSION_PENDING },
],
},
},
});
this.addActiveSessionFilters(filters, availableSessions, sessions);
}
let targets;
let totalItems = 0;
let doTargetsExist = false;
if (this.can.can('list model', scope, { collection: 'targets' })) {
targets = await this.store.query('target', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = targets.meta?.totalItems;
doTargetsExist = await this.getDoTargetsExist(scope_id, totalItems);
}
return { targets, doTargetsExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({
search,
availableSessions,
types,
page,
pageSize,
useDebounce,
}) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
id: { values: [] },
type: [],
};
types.forEach((type) => {
filters.type.push({ equals: type });
});
if (this.can.can('list model', scope, { collection: 'sessions' })) {
const sessions = await this.store.query('session', {
scope_id,
query: {
filters: {
scope_id: [{ equals: scope_id }],
status: [
{ equals: STATUS_SESSION_ACTIVE },
{ equals: STATUS_SESSION_PENDING },
],
},
},
});
this.addActiveSessionFilters(filters, availableSessions, sessions);
}
let targets;
let totalItems = 0;
let doTargetsExist = false;
if (this.can.can('list model', scope, { collection: 'targets' })) {
targets = await this.store.query('target', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = targets.meta?.totalItems;
doTargetsExist = await this.getDoTargetsExist(scope_id, totalItems);
}
return { targets, doTargetsExist, totalItems };
},
);
/**
* Sets doTargetsExist to true if there exists any targets.
* @param {string} scope_id
+36 -23
View File
@@ -5,6 +5,7 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';
import { restartableTask, timeout } from 'ember-concurrency';
export default class ScopesScopeUsersIndexRoute extends Route {
// =attributes
@@ -33,31 +34,43 @@ export default class ScopesScopeUsersIndexRoute extends Route {
* Loads queried users and the number of users under current scope.
* @returns {Promise<{totalItems: number, users: [UserModel], doUsersExist: boolean }> }
*/
async model({ search, page, pageSize }) {
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
};
let users;
let totalItems = 0;
let doUsersExist = false;
if (this.can.can('list model', scope, { collection: 'users' })) {
users = await this.store.query('user', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = users.meta?.totalItems;
doUsersExist = await this.getDoUsersExist(scope_id, totalItems);
}
return { users, doUsersExist, totalItems };
async model(params) {
const useDebounce =
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
return this.retrieveData.perform({ ...params, useDebounce });
}
retrieveData = restartableTask(
async ({ search, page, pageSize, useDebounce }) => {
if (useDebounce) {
await timeout(250);
}
const scope = this.modelFor('scopes.scope');
const { id: scope_id } = scope;
const filters = {
scope_id: [{ equals: scope_id }],
};
let users;
let totalItems = 0;
let doUsersExist = false;
if (this.can.can('list model', scope, { collection: 'users' })) {
users = await this.store.query('user', {
scope_id,
query: { search, filters },
page,
pageSize,
});
totalItems = users.meta?.totalItems;
doUsersExist = await this.getDoUsersExist(scope_id, totalItems);
}
return { users, doUsersExist, totalItems };
},
);
/**
* Sets doUsersExist to true if there exists any users.
* @param {string} scope_id