diff --git a/frontend/src/pages/RunList.test.tsx b/frontend/src/pages/RunList.test.tsx
index 3cee3842b9f..5f524e48b0d 100644
--- a/frontend/src/pages/RunList.test.tsx
+++ b/frontend/src/pages/RunList.test.tsx
@@ -381,6 +381,50 @@ describe('RunList', () => {
expect(Apis.runServiceApi.getRun).toHaveBeenCalledWith('run2');
});
+ it('loads given and filtered list of runs only', async () => {
+ mockNRuns(5, {});
+ const props = generateProps();
+ props.runIdListMask = ['filterRun1', 'filterRun2', 'notincluded'];
+ tree = shallow();
+ await (tree.instance() as RunListTest)._loadRuns({
+ filter: encodeURIComponent(
+ JSON.stringify({
+ predicates: [{ key: 'name', op: PredicateOp.ISSUBSTRING, string_value: 'filterRun' }],
+ }),
+ ),
+ });
+ expect(tree.state('runs')).toMatchObject([
+ {
+ run: { name: 'run with id: filterRun1' },
+ },
+ {
+ run: { name: 'run with id: filterRun2' },
+ },
+ ]);
+ });
+
+ it('loads given and filtered list of runs only through multiple filters', async () => {
+ mockNRuns(5, {});
+ const props = generateProps();
+ props.runIdListMask = ['filterRun1', 'filterRun2', 'notincluded1'];
+ tree = shallow();
+ await (tree.instance() as RunListTest)._loadRuns({
+ filter: encodeURIComponent(
+ JSON.stringify({
+ predicates: [
+ { key: 'name', op: PredicateOp.ISSUBSTRING, string_value: 'filterRun' },
+ { key: 'name', op: PredicateOp.ISSUBSTRING, string_value: '1' },
+ ],
+ }),
+ ),
+ });
+ expect(tree.state('runs')).toMatchObject([
+ {
+ run: { name: 'run with id: filterRun1' },
+ },
+ ]);
+ });
+
it('adds metrics columns', async () => {
mockNRuns(2, {
run: {
diff --git a/frontend/src/pages/RunList.tsx b/frontend/src/pages/RunList.tsx
index a2dc8b45f0b..753c89863ff 100644
--- a/frontend/src/pages/RunList.tsx
+++ b/frontend/src/pages/RunList.tsx
@@ -331,9 +331,24 @@ class RunList extends React.PureComponent {
if (Array.isArray(this.props.runIdListMask)) {
displayRuns = this.props.runIdListMask.map(id => ({ run: { id } }));
- // listRuns doesn't currently support batching by IDs, so in this case we retrieve each run
- // individually.
+ const filter = JSON.parse(
+ decodeURIComponent(request.filter || '{"predicates": []}'),
+ ) as ApiFilter;
+ // listRuns doesn't currently support batching by IDs, so in this case we retrieve and filter
+ // each run individually.
await this._getAndSetRuns(displayRuns);
+ const predicates = filter.predicates?.filter(
+ p => p.key === 'name' && p.op === PredicateOp.ISSUBSTRING,
+ );
+ const substrings = predicates?.map(p => p.string_value?.toLowerCase() || '') || [];
+ displayRuns = displayRuns.filter(runDetail => {
+ for (const sub of substrings) {
+ if (!runDetail?.run?.name?.toLowerCase().includes(sub)) {
+ return false;
+ }
+ }
+ return true;
+ });
} else {
// Load all runs
if (this.props.storageState) {