fix: 🐛 Fix search field race condition in DC targets (#2723)
* fix: 🐛 Fix search field race condition in DC targets * feat: 🎸 Keep track of last search to know when to debounce ✅ Closes: ICU-14775
This commit is contained in:
1 parent
dff5cac4fe
commit
7becccd628
2 files changed
+88
-66
No files matched your search
@@ -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';
|
||||
import orderBy from 'lodash/orderBy';
|
||||
import { TYPES_TARGET } from 'api/models/target';
|
||||
@@ -251,7 +250,6 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle
|
||||
* @param {object} event
|
||||
*/
|
||||
@action
|
||||
@debounce(250)
|
||||
handleSearchInput(event) {
|
||||
const { value } = event.target;
|
||||
this.search = value;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
STATUS_SESSION_PENDING,
|
||||
} from 'api/models/session';
|
||||
import { action } from '@ember/object';
|
||||
import { restartableTask, timeout } from 'ember-concurrency';
|
||||
|
||||
const { __electronLog } = globalThis;
|
||||
|
||||
@@ -82,78 +83,101 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
|
||||
* @return {Promise<{totalItems: number, targets: [TargetModel], projects: [ScopeModel],
|
||||
* isCacheDaemonRunning: boolean, isLoadIncomplete: boolean, isCacheRefreshing: boolean}>}
|
||||
*/
|
||||
async model({ search, scopes, availableSessions, types, page, pageSize }) {
|
||||
const isCacheRunningPromise = this.ipc.invoke('isCacheDaemonRunning');
|
||||
async model(params) {
|
||||
const useDebounce =
|
||||
this.retrieveData?.lastPerformed?.args?.[0].search !== params.search;
|
||||
return this.retrieveData.perform({ ...params, useDebounce });
|
||||
}
|
||||
|
||||
const orgScope = this.modelFor('scopes.scope');
|
||||
const projects = this.modelFor('scopes.scope.projects');
|
||||
|
||||
// orgFilter used to narrow down resources to only those under
|
||||
// the current org scope if org is not global
|
||||
const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`;
|
||||
|
||||
const filters = { scope_id: [], id: { values: [] }, type: [] };
|
||||
scopes.forEach((scope) => {
|
||||
filters.scope_id.push({ equals: scope });
|
||||
});
|
||||
types.forEach((type) => {
|
||||
filters.type.push({ equals: type });
|
||||
});
|
||||
|
||||
const sessions = await this.getSessions(orgScope, scopes, orgFilter);
|
||||
this.addActiveSessionFilters(filters, availableSessions, sessions);
|
||||
|
||||
const query = {
|
||||
recursive: true,
|
||||
scope_id: orgScope.id,
|
||||
query: { search, filters },
|
||||
retrieveData = restartableTask(
|
||||
async ({
|
||||
search,
|
||||
scopes,
|
||||
availableSessions,
|
||||
types,
|
||||
page,
|
||||
pageSize,
|
||||
force_refresh: true,
|
||||
};
|
||||
if (orgScope.isOrg && scopes.length === 0) {
|
||||
query.filter = orgFilter;
|
||||
}
|
||||
let targets = await this.store.query('target', query);
|
||||
const { totalItems, isLoadIncomplete, isCacheRefreshing } = targets.meta;
|
||||
// Filter out targets to which users do not have the connect ability
|
||||
targets = targets.filter((target) =>
|
||||
this.can.can('connect target', target),
|
||||
);
|
||||
useDebounce,
|
||||
}) => {
|
||||
if (useDebounce) {
|
||||
await timeout(250);
|
||||
}
|
||||
|
||||
const aliasPromise = this.store.query('alias', {
|
||||
scope_id: 'global',
|
||||
force_refresh: true,
|
||||
query: {
|
||||
filters: {
|
||||
destination_id: {
|
||||
logicalOperator: 'or',
|
||||
values: targets.map((target) => ({
|
||||
equals: target.id,
|
||||
})),
|
||||
const isCacheRunningPromise = this.ipc.invoke('isCacheDaemonRunning');
|
||||
|
||||
const orgScope = this.modelFor('scopes.scope');
|
||||
const projects = this.modelFor('scopes.scope.projects');
|
||||
|
||||
// orgFilter used to narrow down resources to only those under
|
||||
// the current org scope if org is not global
|
||||
const orgFilter = `"/item/scope/parent_scope_id" == "${orgScope.id}"`;
|
||||
|
||||
const filters = { scope_id: [], id: { values: [] }, type: [] };
|
||||
scopes.forEach((scope) => {
|
||||
filters.scope_id.push({ equals: scope });
|
||||
});
|
||||
types.forEach((type) => {
|
||||
filters.type.push({ equals: type });
|
||||
});
|
||||
|
||||
const sessions = await this.getSessions(orgScope, scopes, orgFilter);
|
||||
this.addActiveSessionFilters(filters, availableSessions, sessions);
|
||||
|
||||
const query = {
|
||||
recursive: true,
|
||||
scope_id: orgScope.id,
|
||||
query: { search, filters },
|
||||
page,
|
||||
pageSize,
|
||||
force_refresh: true,
|
||||
};
|
||||
if (orgScope.isOrg && scopes.length === 0) {
|
||||
query.filter = orgFilter;
|
||||
}
|
||||
let targets = await this.store.query('target', query);
|
||||
const { totalItems, isLoadIncomplete, isCacheRefreshing } = targets.meta;
|
||||
// Filter out targets to which users do not have the connect ability
|
||||
targets = targets.filter((target) =>
|
||||
this.can.can('connect target', target),
|
||||
);
|
||||
|
||||
const aliasPromise = this.store.query('alias', {
|
||||
scope_id: 'global',
|
||||
force_refresh: true,
|
||||
query: {
|
||||
filters: {
|
||||
destination_id: {
|
||||
logicalOperator: 'or',
|
||||
values: targets.map((target) => ({
|
||||
equals: target.id,
|
||||
})),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
// Load the aliases for the targets on the current page
|
||||
try {
|
||||
await aliasPromise;
|
||||
} catch (e) {
|
||||
__electronLog?.warn('Could not retrieve aliases for targets', e.message);
|
||||
// Separately await and catch the error here so we can continue loading
|
||||
// the page in case the controller doesn't support aliases yet
|
||||
}
|
||||
// Load the aliases for the targets on the current page
|
||||
try {
|
||||
await aliasPromise;
|
||||
} catch (e) {
|
||||
__electronLog?.warn(
|
||||
'Could not retrieve aliases for targets',
|
||||
e.message,
|
||||
);
|
||||
// Separately await and catch the error here so we can continue loading
|
||||
// the page in case the controller doesn't support aliases yet
|
||||
}
|
||||
|
||||
return {
|
||||
targets,
|
||||
projects,
|
||||
totalItems,
|
||||
isLoadIncomplete,
|
||||
isCacheRefreshing,
|
||||
isCacheDaemonRunning: await isCacheRunningPromise,
|
||||
};
|
||||
}
|
||||
return {
|
||||
targets,
|
||||
projects,
|
||||
totalItems,
|
||||
isLoadIncomplete,
|
||||
isCacheRefreshing,
|
||||
isCacheDaemonRunning: await isCacheRunningPromise,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
async getSessions(orgScope, scopes, orgFilter) {
|
||||
// Retrieve all sessions so that the session and activeSessions getters
|
||||
|
||||
Reference in new issue
Block a user