feat: 🎸 Add pagination support to client daemon handler (#2016)

✅ Closes: https://hashicorp.atlassian.net/browse/ICU-11743
This commit is contained in:
Zhihe Li committed 2024-01-16 10:17:45 -05:00
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'))