Skip to content

Commit 8bb765d

Browse files
authored
Add filter options to experiment table header context menu (#4415)
1 parent c173279 commit 8bb765d

File tree

10 files changed

+316
-46
lines changed

10 files changed

+316
-46
lines changed

extension/src/experiments/index.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
workspace
88
} from 'vscode'
99
import omit from 'lodash.omit'
10-
import { addStarredToColumns } from './columns/like'
10+
import { ColumnLike, addStarredToColumns } from './columns/like'
1111
import { setContextForEditorTitleIcons } from './context'
1212
import { ExperimentsModel } from './model'
1313
import {
@@ -17,6 +17,7 @@ import {
1717
} from './model/quickPick'
1818
import { pickAndModifyParams } from './model/modify/quickPick'
1919
import {
20+
pickColumnToFilter,
2021
pickFilterToAdd,
2122
pickFiltersToRemove
2223
} from './model/filterBy/quickPick'
@@ -302,11 +303,13 @@ export class Experiments extends BaseRepository<TableData> {
302303
return this.experiments.getFilters()
303304
}
304305

305-
public async addFilter() {
306-
const columns = this.columns.getTerminalNodes()
307-
const columnLikes = addStarredToColumns(columns)
306+
public async addFilter(overrideColumn?: ColumnLike) {
307+
const column = await this.pickColumnToFilter(overrideColumn)
308+
if (!column) {
309+
return
310+
}
308311

309-
const filterToAdd = await pickFilterToAdd(columnLikes)
312+
const filterToAdd = await pickFilterToAdd(column)
310313
if (!filterToAdd) {
311314
return
312315
}
@@ -624,6 +627,7 @@ export class Experiments extends BaseRepository<TableData> {
624627
() => this.selectColumns(),
625628
() => this.selectFirstColumns(),
626629
(branchesSelected: string[]) => this.selectBranches(branchesSelected),
630+
(column: ColumnLike) => this.addFilter(column),
627631
() => this.data.update()
628632
)
629633

@@ -687,4 +691,13 @@ export class Experiments extends BaseRepository<TableData> {
687691
return setUserConfigValue(ConfigKey.DO_NOT_INFORM_MAX_PLOTTED, true)
688692
}
689693
}
694+
695+
private pickColumnToFilter(overrideColumn?: ColumnLike) {
696+
if (overrideColumn) {
697+
return overrideColumn
698+
}
699+
const columns = this.columns.getTerminalNodes()
700+
const columnLikes = addStarredToColumns(columns)
701+
return pickColumnToFilter(columnLikes)
702+
}
690703
}

extension/src/experiments/model/filterBy/quickPick.test.ts

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -47,26 +47,15 @@ const mixedParam = {
4747
}
4848

4949
describe('pickFilterToAdd', () => {
50-
it('should return early if no param or metric is picked', async () => {
51-
const params = [epochsParam]
52-
mockedQuickPickValue.mockResolvedValueOnce(undefined)
53-
const filter = await pickFilterToAdd(params)
54-
expect(filter).toBeUndefined()
55-
})
56-
5750
it('should return early if no operator is picked', async () => {
58-
const params = [epochsParam]
59-
mockedQuickPickValue.mockResolvedValueOnce(epochsParam)
6051
mockedQuickPickValue.mockResolvedValueOnce(undefined)
61-
const filter = await pickFilterToAdd(params)
52+
const filter = await pickFilterToAdd(epochsParam)
6253
expect(filter).toBeUndefined()
6354
})
6455

6556
it('should call showQuickPick with the correct operators for a mixed type param', async () => {
66-
const params = [mixedParam]
67-
mockedQuickPickValue.mockResolvedValueOnce(mixedParam)
6857
mockedQuickPickValue.mockResolvedValueOnce(undefined)
69-
await pickFilterToAdd(params)
58+
await pickFilterToAdd(mixedParam)
7059
expect(mockedQuickPickValue).toHaveBeenCalledWith(
7160
OPERATORS.filter(({ types }) => types.includes('number')),
7261
{
@@ -76,19 +65,15 @@ describe('pickFilterToAdd', () => {
7665
})
7766

7867
it('should return early if no value is provided', async () => {
79-
const params = [epochsParam]
80-
mockedQuickPickValue.mockResolvedValueOnce(epochsParam)
8168
mockedQuickPickValue.mockResolvedValueOnce('==')
8269
mockedGetInput.mockResolvedValueOnce(undefined)
83-
const filter = await pickFilterToAdd(params)
70+
const filter = await pickFilterToAdd(epochsParam)
8471
expect(filter).toBeUndefined()
8572
})
8673

8774
it('should return without asking for a value when a boolean param is selected', async () => {
88-
const params = [boolParam]
89-
mockedQuickPickValue.mockResolvedValueOnce(boolParam)
9075
mockedQuickPickValue.mockResolvedValueOnce(Operator.IS_TRUE)
91-
const filter = await pickFilterToAdd(params)
76+
const filter = await pickFilterToAdd(boolParam)
9277
expect(filter).toStrictEqual({
9378
operator: Operator.IS_TRUE,
9479
path: boolParam.path,
@@ -104,11 +89,9 @@ describe('pickFilterToAdd', () => {
10489
})
10590

10691
it('should return a filter definition if all of the steps are completed', async () => {
107-
const params = [epochsParam]
108-
mockedQuickPickValue.mockResolvedValueOnce(epochsParam)
10992
mockedQuickPickValue.mockResolvedValueOnce('==')
11093
mockedGetInput.mockResolvedValueOnce('5')
111-
const filter = await pickFilterToAdd(params)
94+
const filter = await pickFilterToAdd(epochsParam)
11295
expect(filter).toStrictEqual({
11396
operator: '==',
11497
path: epochsParam.path,

extension/src/experiments/model/filterBy/quickPick.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,19 @@ const addFilterValue = async (path: string, operator: Operator) => {
115115
}
116116
}
117117

118-
export const pickFilterToAdd = async (
118+
export const pickColumnToFilter = (
119119
columns: ColumnLike[] | undefined
120-
): Promise<FilterDefinition | undefined> => {
121-
const picked = await pickFromColumnLikes(columns, {
120+
): Thenable<ColumnLike | undefined> =>
121+
pickFromColumnLikes(columns, {
122122
title: Title.SELECT_PARAM_OR_METRIC_FILTER
123123
})
124-
if (!picked) {
125-
return
126-
}
127124

125+
export const pickFilterToAdd = async ({
126+
firstValueType,
127+
path
128+
}: ColumnLike): Promise<FilterDefinition | undefined> => {
128129
const typedOperators = OPERATORS.filter(
129-
operator =>
130-
picked.firstValueType && operator.types.includes(picked.firstValueType)
130+
operator => firstValueType && operator.types.includes(firstValueType)
131131
)
132132

133133
const operator = await quickPickValue<Operator>(typedOperators, {
@@ -144,12 +144,12 @@ export const pickFilterToAdd = async (
144144
) {
145145
return {
146146
operator,
147-
path: picked.path,
147+
path,
148148
value: undefined
149149
}
150150
}
151151

152-
return addFilterValue(picked.path, operator)
152+
return addFilterValue(path, operator)
153153
}
154154

155155
export const pickFiltersToRemove = (

extension/src/experiments/webview/messages.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import { ConfigKey, setConfigValue } from '../../vscode/config'
2323
import { NUM_OF_COMMITS_TO_INCREASE } from '../../cli/dvc/constants'
2424
import { Pipeline } from '../../pipeline'
2525
import { collectColumnsWithChangedValues } from '../columns/collect'
26+
import { ColumnLike } from '../columns/like'
27+
import { getFilterId } from '../model/filterBy'
2628

2729
export class WebviewMessages {
2830
private readonly dvcRoot: string
@@ -35,7 +37,7 @@ export class WebviewMessages {
3537
private readonly notifyChanged: () => void
3638
private readonly selectColumns: () => Promise<void>
3739
private readonly selectFirstColumns: () => Promise<void>
38-
40+
private readonly addFilter: (column: ColumnLike) => Promise<void>
3941
private readonly selectBranches: (
4042
branchesSelected: string[]
4143
) => Promise<string[] | undefined>
@@ -54,6 +56,7 @@ export class WebviewMessages {
5456
selectBranches: (
5557
branchesSelected: string[]
5658
) => Promise<string[] | undefined>,
59+
addFilter: (column: ColumnLike) => Promise<void>,
5760
update: () => Promise<void>
5861
) {
5962
this.dvcRoot = dvcRoot
@@ -65,6 +68,7 @@ export class WebviewMessages {
6568
this.selectColumns = selectColumns
6669
this.selectFirstColumns = selectFirstColumns
6770
this.selectBranches = selectBranches
71+
this.addFilter = addFilter
6872
this.update = update
6973
}
7074

@@ -101,6 +105,11 @@ export class WebviewMessages {
101105
return this.addColumnSort(message.payload)
102106
case MessageFromWebviewType.REMOVE_COLUMN_SORT:
103107
return this.removeColumnSort(message.payload)
108+
case MessageFromWebviewType.FILTER_COLUMN:
109+
return this.addColumnFilter(message.payload)
110+
case MessageFromWebviewType.REMOVE_COLUMN_FILTERS:
111+
return this.removeColumnFilter(message.payload)
112+
104113
case MessageFromWebviewType.APPLY_EXPERIMENT_TO_WORKSPACE:
105114
return commands.executeCommand(
106115
RegisteredCliCommands.EXPERIMENT_VIEW_APPLY,
@@ -434,6 +443,40 @@ export class WebviewMessages {
434443
return this.notifyChanged()
435444
}
436445

446+
private addColumnFilter(selectedPath: string) {
447+
const column = this.columns
448+
.getTerminalNodes()
449+
.find(({ path }) => path === selectedPath)
450+
451+
if (!column) {
452+
return
453+
}
454+
455+
void this.addFilter(column)
456+
457+
sendTelemetryEvent(
458+
EventName.VIEWS_EXPERIMENTS_TABLE_FILTER_COLUMN,
459+
undefined,
460+
undefined
461+
)
462+
}
463+
464+
private removeColumnFilter(selectedPath: string) {
465+
for (const filter of this.experiments.getFilters()) {
466+
if (filter.path === selectedPath) {
467+
const id = getFilterId(filter)
468+
this.experiments.removeFilter(id)
469+
}
470+
}
471+
this.notifyChanged()
472+
473+
sendTelemetryEvent(
474+
EventName.VIEWS_EXPERIMENTS_TABLE_REMOVE_COLUMN_FILTER,
475+
undefined,
476+
undefined
477+
)
478+
}
479+
437480
private focusSortsTree() {
438481
const commandPromise = commands.executeCommand(
439482
'dvc.views.experimentsSortByTree.focus'

extension/src/telemetry/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const EventName = Object.assign(
3737
'views.experimentTable.toggleStars',
3838
VIEWS_EXPERIMENTS_TABLE_EXPERIMENT_TOGGLE:
3939
'views.experimentTable.toggleStatus',
40+
VIEWS_EXPERIMENTS_TABLE_FILTER_COLUMN: 'views.experimentTable.filterColumn',
4041
VIEWS_EXPERIMENTS_TABLE_FOCUS_CHANGED:
4142
'views.experimentsTable.focusChanged',
4243
VIEWS_EXPERIMENTS_TABLE_FOCUS_FILTERS_TREE:
@@ -49,6 +50,8 @@ export const EventName = Object.assign(
4950
VIEWS_EXPERIMENTS_TABLE_OPEN_PARAMS_FILE:
5051
'views.experimentsTable.paramsFileOpened',
5152
VIEWS_EXPERIMENTS_TABLE_REFRESH: 'views.experimentsTable.refresh',
53+
VIEWS_EXPERIMENTS_TABLE_REMOVE_COLUMN_FILTER:
54+
'views.experimentsTable.removeColumnFilter',
5255
VIEWS_EXPERIMENTS_TABLE_REMOVE_COLUMN_SORT:
5356
'views.experimentsTable.columnSortRemoved',
5457
VIEWS_EXPERIMENTS_TABLE_RESET_COMMITS:
@@ -252,6 +255,8 @@ export interface IEventNamePropertyMapping {
252255
}
253256
[EventName.VIEWS_EXPERIMENTS_TABLE_RESET_COMMITS]: undefined
254257
[EventName.VIEWS_EXPERIMENTS_TABLE_CREATED]: undefined
258+
[EventName.VIEWS_EXPERIMENTS_TABLE_FILTER_COLUMN]: undefined
259+
[EventName.VIEWS_EXPERIMENTS_TABLE_REMOVE_COLUMN_FILTER]: undefined
255260
[EventName.VIEWS_EXPERIMENTS_TABLE_FOCUS_CHANGED]: WebviewFocusChangedProperties
256261
[EventName.VIEWS_EXPERIMENTS_TABLE_HIDE_COLUMN_PATH]: {
257262
path: string

0 commit comments

Comments
 (0)