Skip to content

Commit c1fd446

Browse files
authored
Add constant to verify if there is a custom selection of plots (#4989)
* Add constant to check if there previously was a custom selection of plots * Add tests * Added more testsM * Stub other functions
1 parent eb5e851 commit c1fd446

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed

extension/src/persistence/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export enum PersistenceKey {
1515
PLOT_METRIC_ORDER = 'plotMetricOrder:',
1616
PLOT_NB_ITEMS_PER_ROW_OR_WIDTH = 'plotNbItemsPerRowOrWidth:',
1717
PLOTS_CUSTOM_ORDER = 'plotCustomOrder:',
18+
PLOTS_HAS_CUSTOM_SELECTION = 'plotsCustomCollection:',
1819
PLOT_SECTION_COLLAPSED = 'plotSectionCollapsed:',
1920
PLOT_SELECTED_METRICS = 'plotSelectedMetrics:',
2021
PLOTS_SMOOTH_PLOT_VALUES = 'plotSmoothPlotValues:',

extension/src/plots/index.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export class Plots extends BaseRepository<TPlotsData> {
9191
const status = this.paths.toggleStatus(path)
9292
this.paths.setTemplateOrder()
9393
this.notifyChanged()
94+
this.setHasCustomSelection()
9495
return status
9596
}
9697

@@ -104,6 +105,7 @@ export class Plots extends BaseRepository<TPlotsData> {
104105

105106
this.paths.setSelected(selected)
106107
this.paths.setTemplateOrder()
108+
this.setHasCustomSelection()
107109
return this.notifyChanged()
108110
}
109111

@@ -170,6 +172,10 @@ export class Plots extends BaseRepository<TPlotsData> {
170172
return this.sendPlots()
171173
}
172174

175+
private setHasCustomSelection() {
176+
this.paths.setHasCustomSelection(this.paths.getTerminalNodes().length > 20)
177+
}
178+
173179
private notifyChanged() {
174180
const selectedRevisions = this.plots.getSelectedRevisionIds()
175181
this.paths.setSelectedRevisions(selectedRevisions)
@@ -244,6 +250,7 @@ export class Plots extends BaseRepository<TPlotsData> {
244250
collectInitialIdShas()
245251
this.setupExperimentsListener(experiments)
246252
void this.initializeData()
253+
this.paths.checkIfHasPreviousCustomSelection()
247254
})
248255
)
249256
}

extension/src/plots/paths/model.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import { EXPERIMENT_WORKSPACE_ID } from '../../cli/dvc/contract'
88
import { ErrorsModel } from '../errors/model'
99
import { REVISIONS } from '../../test/fixtures/plotsDiff'
1010
import { SpecWithTitles } from '../vega/util'
11+
import { PersistenceKey } from '../../persistence/constants'
12+
import { Status } from '../../path/selection/model'
1113

1214
describe('PathsModel', () => {
1315
const mockDvcRoot = 'test'
@@ -502,4 +504,75 @@ describe('PathsModel', () => {
502504

503505
expect(model.getTerminalNodes()).toStrictEqual([])
504506
})
507+
508+
it('should not change hasCustomSelection when checking for if it is already defined', () => {
509+
const memento = buildMockMemento({
510+
[PersistenceKey.PLOTS_HAS_CUSTOM_SELECTION + mockDvcRoot]: true
511+
})
512+
const model = new PathsModel(mockDvcRoot, buildMockErrorsModel(), memento)
513+
const setHasCustomSelectionSpy = jest.spyOn(model, 'setHasCustomSelection')
514+
515+
model.checkIfHasPreviousCustomSelection()
516+
expect(setHasCustomSelectionSpy).not.toHaveBeenCalled()
517+
})
518+
519+
it('should set hasCustomSelection to false if there are less than 20 plots', () => {
520+
const model = new PathsModel(
521+
mockDvcRoot,
522+
buildMockErrorsModel(),
523+
buildMockMemento()
524+
)
525+
const setHasCustomSelectionSpy = jest.spyOn(model, 'setHasCustomSelection')
526+
jest
527+
.spyOn(model, 'getTerminalNodeStatuses')
528+
.mockImplementation(() => [
529+
Status.SELECTED,
530+
Status.SELECTED,
531+
Status.SELECTED,
532+
Status.SELECTED
533+
])
534+
535+
model.checkIfHasPreviousCustomSelection()
536+
expect(setHasCustomSelectionSpy).toHaveBeenCalledWith(false)
537+
})
538+
539+
it('should set hasCustomSelection to false if there are 20 selected plots', () => {
540+
const model = new PathsModel(
541+
mockDvcRoot,
542+
buildMockErrorsModel(),
543+
buildMockMemento()
544+
)
545+
const setHasCustomSelectionSpy = jest.spyOn(model, 'setHasCustomSelection')
546+
const statuses = [Status.UNSELECTED]
547+
for (let i = 0; i < 20; i++) {
548+
statuses.push(Status.SELECTED)
549+
}
550+
statuses.push(Status.UNSELECTED)
551+
jest
552+
.spyOn(model, 'getTerminalNodeStatuses')
553+
.mockImplementation(() => statuses)
554+
555+
model.checkIfHasPreviousCustomSelection()
556+
expect(setHasCustomSelectionSpy).toHaveBeenCalledWith(false)
557+
})
558+
559+
it('should set hasCustomSelection to true if there are more than 20 plots and the number of selected plots is not 20', () => {
560+
const model = new PathsModel(
561+
mockDvcRoot,
562+
buildMockErrorsModel(),
563+
buildMockMemento()
564+
)
565+
const setHasCustomSelectionSpy = jest.spyOn(model, 'setHasCustomSelection')
566+
const statuses = [Status.UNSELECTED]
567+
for (let i = 0; i < 19; i++) {
568+
statuses.push(Status.SELECTED)
569+
}
570+
statuses.push(Status.UNSELECTED)
571+
jest
572+
.spyOn(model, 'getTerminalNodeStatuses')
573+
.mockImplementation(() => statuses)
574+
575+
model.checkIfHasPreviousCustomSelection()
576+
expect(setHasCustomSelectionSpy).toHaveBeenCalledWith(true)
577+
})
505578
})

extension/src/plots/paths/model.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ export class PathsModel extends PathSelectionModel<PlotPath> {
2727

2828
private selectedRevisions: string[] = []
2929

30+
private hasCustomSelection: boolean | undefined = undefined
31+
3032
constructor(dvcRoot: string, errors: ErrorsModel, workspaceState: Memento) {
3133
super(dvcRoot, workspaceState, PersistenceKey.PLOT_PATH_STATUS)
3234

@@ -37,6 +39,11 @@ export class PathsModel extends PathSelectionModel<PlotPath> {
3739
PersistenceKey.PLOT_COMPARISON_PATHS_ORDER,
3840
[]
3941
)
42+
43+
this.hasCustomSelection = this.revive(
44+
PersistenceKey.PLOTS_HAS_CUSTOM_SELECTION,
45+
undefined
46+
)
4047
}
4148

4249
public setSelectedRevisions(selectedRevisions: string[]) {
@@ -144,6 +151,30 @@ export class PathsModel extends PathSelectionModel<PlotPath> {
144151
return this.data.length > 0
145152
}
146153

154+
public setHasCustomSelection(hasCustomSelection: boolean) {
155+
this.hasCustomSelection = hasCustomSelection
156+
this.persist(
157+
PersistenceKey.PLOTS_HAS_CUSTOM_SELECTION,
158+
this.hasCustomSelection
159+
)
160+
}
161+
162+
public checkIfHasPreviousCustomSelection() {
163+
if (this.hasCustomSelection === undefined) {
164+
const statuses = this.getTerminalNodeStatuses()
165+
const plotsLength = statuses.length
166+
167+
const hasCustomSelection =
168+
plotsLength > 20
169+
? plotsLength -
170+
statuses.filter(nodeStatus => nodeStatus !== Status.SELECTED)
171+
.length !==
172+
20
173+
: false
174+
this.setHasCustomSelection(hasCustomSelection)
175+
}
176+
}
177+
147178
private handleCliError() {
148179
this.data = []
149180
}

extension/src/test/suite/plots/index.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,16 @@ import { BaseWebview } from '../../../webview'
5555
import * as PlotsCollectUtils from '../../../plots/model/collect'
5656
import { Operator } from '../../../experiments/model/filterBy'
5757
import * as External from '../../../vscode/external'
58+
import { PlotPath } from '../../../plots/paths/collect'
5859

5960
suite('Plots Test Suite', () => {
6061
const disposable = Disposable.fn()
6162

63+
const createTerminalNodesArray = (length: number) =>
64+
Array.from({ length }, i => ({ path: i })) as unknown as (PlotPath & {
65+
selected: boolean
66+
})[]
67+
6268
beforeEach(() => {
6369
restore()
6470
})
@@ -1304,5 +1310,35 @@ suite('Plots Test Suite', () => {
13041310
'should no long provide decorations to the plots paths tree'
13051311
).to.deep.equal(new Set([]))
13061312
})
1313+
1314+
it('should togglePathStatus to true when calling selectPlots with more than 20 plots', async () => {
1315+
const { plots, pathsModel } = await buildPlotsWebview({
1316+
disposer: disposable,
1317+
plotsDiff: plotsDiffFixture
1318+
})
1319+
const mockSetCustomSelection = stub(pathsModel, 'setHasCustomSelection')
1320+
stub(pathsModel, 'setTemplateOrder')
1321+
stub(pathsModel, 'toggleStatus')
1322+
stub(pathsModel, 'getTerminalNodes').returns(createTerminalNodesArray(32))
1323+
1324+
plots.togglePathStatus(dvcDemoPath)
1325+
1326+
expect(mockSetCustomSelection).to.be.calledWith(true)
1327+
})
1328+
1329+
it('should togglePathStatus to false when calling selectPlots with 20 plots or less', async () => {
1330+
const { plots, pathsModel } = await buildPlotsWebview({
1331+
disposer: disposable,
1332+
plotsDiff: plotsDiffFixture
1333+
})
1334+
const mockSetCustomSelection = stub(pathsModel, 'setHasCustomSelection')
1335+
stub(pathsModel, 'setTemplateOrder')
1336+
stub(pathsModel, 'toggleStatus')
1337+
stub(pathsModel, 'getTerminalNodes').returns(createTerminalNodesArray(20))
1338+
1339+
plots.togglePathStatus(dvcDemoPath)
1340+
1341+
expect(mockSetCustomSelection).to.be.calledWith(false)
1342+
})
13071343
})
13081344
})

0 commit comments

Comments
 (0)