feat: 🎸 Add pagination support to client daemon handler (#2016)
✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11743
This commit is contained in:
1 parent
1135f88cb7
commit
3f11019ef0
4 files changed
+49
-13
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { pluralize } from 'ember-inflector';
|
||||
import { generateMQLExpression } from '../utils/mqlQuery';
|
||||
import ArrayProxy from '@ember/array/proxy';
|
||||
|
||||
/**
|
||||
* Not all types are yet supported by the client daemon so we'll
|
||||
@@ -21,7 +22,7 @@ const ClientDaemonHandler = {
|
||||
switch (context.request.op) {
|
||||
case 'query': {
|
||||
const { store, data } = context.request;
|
||||
const { type, query } = data;
|
||||
const { type, query, options: { pushToStore = true } = {} } = data;
|
||||
const isClientDaemonRunning = await this.ipc.invoke(
|
||||
'isClientDaemonRunning',
|
||||
);
|
||||
@@ -36,7 +37,7 @@ const ClientDaemonHandler = {
|
||||
// TODO: Remove usages of recursive from callers and scope_id since
|
||||
// all calls to daemon are recursive, scope_id can be part of search query instead
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let { recursive, scope_id, ...remainingQuery } = query;
|
||||
let { recursive, scope_id, page, pageSize, ...remainingQuery } = query;
|
||||
let searchQuery = '';
|
||||
if (remainingQuery.query) {
|
||||
const { search, filters } = remainingQuery.query;
|
||||
@@ -63,7 +64,7 @@ const ClientDaemonHandler = {
|
||||
const [results] = Object.values(
|
||||
await this.ipc.invoke('searchClientDaemon', remainingQuery),
|
||||
);
|
||||
const payload = { items: results ?? [] };
|
||||
const payload = { items: paginateResults(results, page, pageSize) };
|
||||
|
||||
const schema = store.modelFor(type);
|
||||
const serializer = store.serializerFor(type);
|
||||
@@ -75,9 +76,18 @@ const ClientDaemonHandler = {
|
||||
'query',
|
||||
);
|
||||
|
||||
// TODO: Add some pagination
|
||||
// Return the raw data if we don't push to the store.
|
||||
let records = normalizedPayload.data;
|
||||
if (pushToStore) {
|
||||
records = store.push(normalizedPayload);
|
||||
}
|
||||
|
||||
return store.push(normalizedPayload);
|
||||
// Use a proxy array to store the metadata so the store's `query`
|
||||
// array requirement is satisfied.
|
||||
return ArrayProxy.create({
|
||||
content: records,
|
||||
meta: { totalItems: results?.length ?? 0 },
|
||||
});
|
||||
}
|
||||
default:
|
||||
return next(context.request);
|
||||
@@ -85,4 +95,29 @@ const ClientDaemonHandler = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes an array and the current page and pagesize to calculate the correct
|
||||
* number of results to return to the caller.
|
||||
*
|
||||
* @param array
|
||||
* @param page
|
||||
* @param pageSize
|
||||
* @returns {[*]}
|
||||
*/
|
||||
const paginateResults = (array, page, pageSize) => {
|
||||
const length = array?.length;
|
||||
if (!array || length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (!page || !pageSize) {
|
||||
return array;
|
||||
}
|
||||
|
||||
const offset = (page - 1) * pageSize;
|
||||
const start = Math.min(length - 1, offset);
|
||||
const end = Math.min(length, offset + pageSize);
|
||||
|
||||
return array.slice(start, end);
|
||||
};
|
||||
|
||||
export default ClientDaemonHandler;
|
||||
@@ -33,7 +33,7 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get noResults() {
|
||||
return this.model.length === 0 && this.search;
|
||||
return this.model.targets.length === 0 && this.search;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ export default class ScopesScopeProjectsTargetsIndexController extends Controlle
|
||||
* @returns {boolean}
|
||||
*/
|
||||
get noTargets() {
|
||||
return this.model.length === 0 && !this.search;
|
||||
return this.model.targets.length === 0 && !this.search;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,9 +35,9 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all targets under current scope.
|
||||
* Loads all targets and the number of targets under current scope.
|
||||
*
|
||||
* @return {Promise{[TargetModel]}}
|
||||
* @returns {Promise<{totalItems: number, targets: [TargetModel]}>}
|
||||
*/
|
||||
async model({ search = '' }) {
|
||||
// TODO: Filter targets by scope we're in manually
|
||||
@@ -45,12 +45,13 @@ export default class ScopesScopeProjectsTargetsIndexRoute extends Route {
|
||||
const queryOptions = { query: { search } };
|
||||
|
||||
let targets = await this.store.query('target', queryOptions);
|
||||
const totalItems = targets.meta?.totalItems;
|
||||
|
||||
// Filter out targets to which users do not have the connect ability
|
||||
targets = targets.filter((target) =>
|
||||
this.can.can('connect target', target),
|
||||
);
|
||||
|
||||
return targets;
|
||||
return { targets: targets, totalItems };
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
</page.header>
|
||||
|
||||
<page.body class='targets'>
|
||||
{{#if (or @model this.search)}}
|
||||
{{#if (or @model.targets this.search)}}
|
||||
<div class='target-search-filtering'>
|
||||
<Hds::SegmentedGroup as |S|>
|
||||
<S.TextInput
|
||||
@@ -54,9 +54,9 @@
|
||||
</S.Dropdown>
|
||||
</Hds::SegmentedGroup>
|
||||
</div>
|
||||
{{#if @model}}
|
||||
{{#if @model.targets}}
|
||||
<Hds::Table
|
||||
@model={{@model}}
|
||||
@model={{@model.targets}}
|
||||
@columns={{array
|
||||
(hash label=(t 'form.name.label'))
|
||||
(hash label=(t 'form.id.label'))
|
||||
|
||||
Reference in new issue
Block a user