Skip to content

Commit

Permalink
[1/2][eas-cli] paginated progress bar (#2326)
Browse files Browse the repository at this point in the history
* [eas-cli] paginated progress bar

* update CHANGELOG.md
  • Loading branch information
quinlanj committed Apr 15, 2024
1 parent d05142f commit a8cde5e
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ This is the log of notable changes to EAS CLI and related packages.

### 🧹 Chores

- Add progress bar for fetching paginated datasets. ([#2326](https://github.com/expo/eas-cli/pull/2326) by [@quinlanj](https://github.com/quinlanj))

## [7.8.1](https://github.com/expo/eas-cli/releases/tag/v7.8.1) - 2024-04-11

### 🐛 Bug fixes
Expand Down
57 changes: 57 additions & 0 deletions packages/eas-cli/src/utils/__tests__/relay-test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { PageInfo } from '../../graphql/generated';
import { promptAsync } from '../../prompts';
import {
Connection,
Edge,
FilterPagination,
NEXT_PAGE_OPTION,
PAGE_SIZE,
PREV_PAGE_OPTION,
PaginatedGetterAsync,
QueryParams,
fetchEntireDatasetAsync,
selectPaginatedAsync,
} from '../relay';

Expand Down Expand Up @@ -780,3 +785,55 @@ describe(selectPaginatedAsync, () => {
expect(getTitleAsync).toHaveBeenCalledWith(node3);
});
});

describe(selectPaginatedAsync, () => {
const mockDataset = Array.from({ length: 50 }, (_, idx) => ({ id: idx + 1 }));
const testPaginatedGetterAsync: PaginatedGetterAsync<object> = async (
relayArgs: QueryParams
): Promise<Connection<object>> => {
const startIdx = relayArgs.after ? Number(relayArgs.after) : 0;
const endIdx = startIdx + (relayArgs.first || PAGE_SIZE);
const hasNextPage = endIdx < mockDataset.length;
const hasPreviousPage = startIdx > 0;
const edges: Edge<object>[] = mockDataset
.slice(startIdx, endIdx)
.map(node => ({ cursor: String(node.id), node }));

const pageInfo: PageInfo = {
hasNextPage,
hasPreviousPage,
endCursor: hasNextPage ? String(endIdx) : undefined,
};

return {
edges,
pageInfo,
};
};

afterEach(() => {
jest.clearAllMocks();
});

test('getting an entire paginated dataset', async () => {
const data = await fetchEntireDatasetAsync({
paginatedGetterAsync: testPaginatedGetterAsync,
});
expect(data).toEqual(mockDataset);
});
test('getting an empty paginated dataset', async () => {
const emptyPaginatedGetterAsync = async (): Promise<Connection<object>> => {
return {
edges: [],
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
},
};
};
const data = await fetchEntireDatasetAsync({
paginatedGetterAsync: emptyPaginatedGetterAsync,
});
expect(data).toEqual([]);
});
});
49 changes: 49 additions & 0 deletions packages/eas-cli/src/utils/relay.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import assert from 'assert';
import cliProgress from 'cli-progress';

import { PageInfo } from '../graphql/generated';
import { promptAsync } from '../prompts';
Expand Down Expand Up @@ -356,3 +357,51 @@ async function selectPaginatedInternalAsync<T>({
return selectedItem as T;
}
}

export type PaginatedGetterAsync<Node> = (relayArgs: QueryParams) => Promise<Connection<Node>>;
export const PAGE_SIZE = 20;
export async function fetchEntireDatasetAsync<Node>({
paginatedGetterAsync,
progressBarLabel,
}: {
paginatedGetterAsync: PaginatedGetterAsync<Node>;
progressBarLabel?: string;
}): Promise<Node[]> {
// No way to know the total count of items beforehand
let totalEstimatedWork = 10;
const queueProgressBar = new cliProgress.SingleBar(
{ format: `|{bar}| ${progressBarLabel}` },
cliProgress.Presets.rect
);

const data: Node[] = [];
let cursor = undefined;
let didStartProgressBar = false;
let progress = 0;
while (true) {
const connection = await paginatedGetterAsync({ first: PAGE_SIZE, after: cursor });
const nodes = connection.edges.map(edge => edge.node);
const hasNextPage = connection.pageInfo.hasNextPage;
data.push(...nodes);
if (!hasNextPage) {
break;
}
cursor = connection.pageInfo.endCursor ?? undefined;
if (!didStartProgressBar) {
// only show the progress bar if user has more than 1 page of items
queueProgressBar.start(totalEstimatedWork, 0);
didStartProgressBar = true;
}
progress++;
queueProgressBar.update(progress);
if (progress >= totalEstimatedWork) {
totalEstimatedWork = 8 * totalEstimatedWork;
queueProgressBar.setTotal(totalEstimatedWork);
}
}
if (didStartProgressBar) {
queueProgressBar.update(totalEstimatedWork);
queueProgressBar.stop();
}
return data;
}

0 comments on commit a8cde5e

Please sign in to comment.