Skip to content

Commit

Permalink
Merge branch 'main' into sticky-table-header
Browse files Browse the repository at this point in the history
  • Loading branch information
mattseddon authored Jun 2, 2022
2 parents f00726b + 796180c commit 6138da2
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 94 deletions.
2 changes: 1 addition & 1 deletion extension/package.nls.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"displayName": "DVC",
"description": "DVC VS Code extension",
"description": "Machine learning experiment management with tracking, plots, and data versioning.",
"command.addExperimentsTableFilter": "Add Filter To Experiments Table",
"command.addExperimentsTableSort": "Add Or Update Sort On Experiments Table",
"command.addTarget": "Add Target",
Expand Down
2 changes: 2 additions & 0 deletions webview/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
"@tippyjs/react": "^4.2.6",
"@vscode/webview-ui-toolkit": "^1.0.0",
"classnames": "^2.2.6",
"lodash.clonedeep": "^4.5.0",
"lodash.merge": "^4.6.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-table": "^7.7.0",
Expand Down
22 changes: 3 additions & 19 deletions webview/src/plots/components/Plots.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { PlotSize, Section } from 'dvc/src/plots/webview/contract'
import { MessageFromWebviewType } from 'dvc/src/webview/contract'
import React, { useEffect, useRef, useState, useCallback } from 'react'
import VegaLite, { VegaLiteProps } from 'react-vega/lib/VegaLite'
import { Config } from 'vega-lite'
import styles from './styles.module.scss'
import { VegaLiteProps } from 'react-vega/lib/VegaLite'
import { PlotsSizeProvider } from './PlotsSizeContext'
import { AddPlots, Welcome } from './GetStarted'
import { ZoomedInPlot } from './ZoomedInPlot'
import { CheckpointPlotsWrapper } from './checkpointPlots/CheckpointPlotsWrapper'
import { TemplatePlotsWrapper } from './templatePlots/TemplatePlotsWrapper'
import { ComparisonTableWrapper } from './comparisonTable/ComparisonTableWrapper'
Expand All @@ -16,7 +15,6 @@ import { Modal } from '../../shared/components/modal/Modal'
import { WebviewWrapper } from '../../shared/components/webviewWrapper/WebviewWrapper'
import { DragDropProvider } from '../../shared/components/dragDrop/DragDropContext'
import { sendMessage } from '../../shared/vscode'
import { getThemeValue, ThemeProperty } from '../../util/styles'
import { GetStarted } from '../../shared/components/getStarted/GetStarted'

interface PlotsProps {
Expand Down Expand Up @@ -153,21 +151,7 @@ const PlotsContent = ({ state }: PlotsProps) => {

{zoomedInPlot && (
<Modal onClose={handleModalClose}>
<div className={styles.zoomedInPlot} data-testid="zoomed-in-plot">
<VegaLite
{...zoomedInPlot}
config={{
...(zoomedInPlot.config as Config),
background: getThemeValue(ThemeProperty.MENU_BACKGROUND)
}}
actions={{
compiled: false,
editor: false,
export: true,
source: false
}}
/>
</div>
<ZoomedInPlot props={zoomedInPlot} />
</Modal>
)}
</>
Expand Down
36 changes: 36 additions & 0 deletions webview/src/plots/components/ZoomedInPlot.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react'
import VegaLite, { VegaLiteProps } from 'react-vega/lib/VegaLite'
import { Config } from 'vega-lite'
import merge from 'lodash.merge'
import cloneDeep from 'lodash.clonedeep'
import styles from './styles.module.scss'
import { getThemeValue, ThemeProperty } from '../../util/styles'

export type ZoomedInPlotProps = {
props: VegaLiteProps
}

export const ZoomedInPlot: React.FC<ZoomedInPlotProps> = ({
props
}: ZoomedInPlotProps) => (
<div className={styles.zoomedInPlot} data-testid="zoomed-in-plot">
<VegaLite
{...merge(
{ ...cloneDeep(props) },
{
spec: { encoding: { color: { legend: { disable: false } } } }
}
)}
config={{
...(props.config as Config),
background: getThemeValue(ThemeProperty.MENU_BACKGROUND)
}}
actions={{
compiled: false,
editor: false,
export: true,
source: false
}}
/>
</div>
)
150 changes: 77 additions & 73 deletions webview/src/plots/components/checkpointPlots/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,86 +4,90 @@ import { ColorScale } from 'dvc/src/plots/webview/contract'
export const createSpec = (
title: string,
scale?: ColorScale
): VisualizationSpec => ({
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
data: { name: 'values' },
encoding: {
x: {
axis: { format: '0d', tickMinStep: 1 },
field: 'iteration',
title: 'iteration',
type: 'quantitative'
): VisualizationSpec =>
({
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
data: { name: 'values' },
encoding: {
color: {
field: 'group',
legend: { disable: true },
scale,
title: 'rev',
type: 'nominal'
},
x: {
axis: { format: '0d', tickMinStep: 1 },
field: 'iteration',
title: 'iteration',
type: 'quantitative'
},
y: {
field: 'y',
scale: { zero: false },
title,
type: 'quantitative'
}
},
y: {
field: 'y',
scale: { zero: false },
title,
type: 'quantitative'
}
},
height: 'container',
layer: [
{
encoding: {
color: { field: 'group', legend: null, scale, type: 'nominal' }
height: 'container',
layer: [
{
layer: [
{ mark: { type: 'line' } },
{
mark: { type: 'point' },
transform: [
{
filter: { empty: false, param: 'hover' }
}
]
}
]
},

layer: [
{ mark: { type: 'line' } },
{
mark: { type: 'point' },
transform: [
{
encoding: {
opacity: { value: 0 },
tooltip: [
{ field: 'group', title: 'name' },
{
filter: { empty: false, param: 'hover' }
field: 'y',
title: title.slice(Math.max(0, title.indexOf(':') + 1)),
type: 'quantitative'
}
]
}
]
},
{
encoding: {
opacity: { value: 0 },
tooltip: [
{ field: 'group', title: 'name' },
},
mark: { type: 'rule' },
params: [
{
field: 'y',
title: title.slice(Math.max(0, title.indexOf(':') + 1)),
type: 'quantitative'
name: 'hover',
select: {
clear: 'mouseout',
fields: ['iteration', 'y'],
nearest: true,
on: 'mouseover',
type: 'point'
}
}
]
},
mark: { type: 'rule' },
params: [
{
name: 'hover',
select: {
clear: 'mouseout',
fields: ['iteration', 'y'],
nearest: true,
on: 'mouseover',
type: 'point'
{
encoding: {
color: { field: 'group', scale },
x: { aggregate: 'max', field: 'iteration', type: 'quantitative' },
y: {
aggregate: { argmax: 'iteration' },
field: 'y',
type: 'quantitative'
}
}
]
},
{
encoding: {
color: { field: 'group', scale },
x: { aggregate: 'max', field: 'iteration', type: 'quantitative' },
y: {
aggregate: { argmax: 'iteration' },
field: 'y',
type: 'quantitative'
}
},
mark: { stroke: null, type: 'circle' }
}
],
transform: [
{
as: 'y',
calculate: "format(datum['y'],'.5f')"
}
],
width: 'container'
})
},
mark: { stroke: null, type: 'circle' }
}
],
transform: [
{
as: 'y',
calculate: "format(datum['y'],'.5f')"
}
],
width: 'container'
} as VisualizationSpec)
35 changes: 35 additions & 0 deletions webview/src/shared/components/modal/Modal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @jest-environment jsdom
*/
import React from 'react'
import { render, cleanup, fireEvent } from '@testing-library/react'
import { Modal } from './Modal'

describe('Modal', () => {
afterEach(() => {
cleanup()
})

it('should call the onClose prop when pressing Escape', () => {
const onClose = jest.fn()

render(<Modal onClose={onClose} />)

fireEvent.keyDown(window, { key: 'Escape' })

expect(onClose).toHaveBeenCalled()
})

it('should not call the onClose prop when pressing other keys', () => {
const onClose = jest.fn()

render(<Modal onClose={onClose} />)

fireEvent.keyDown(window, { key: 'Enter' })
fireEvent.keyDown(window, { key: 'e' })
fireEvent.keyDown(window, { key: 'Space' })
fireEvent.keyDown(window, { key: 'Alt' })

expect(onClose).not.toHaveBeenCalled()
})
})
14 changes: 13 additions & 1 deletion webview/src/shared/components/modal/Modal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { MouseEvent } from 'react'
import React, { MouseEvent, useEffect } from 'react'
import styles from './styles.module.scss'
import { AllIcons, Icon } from '../Icon'

Expand All @@ -7,6 +7,18 @@ interface ModalProps {
}

export const Modal: React.FC<ModalProps> = ({ onClose, children }) => {
useEffect(() => {
const checkKeyAndClose = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose()
}
}
window.addEventListener('keydown', checkKeyAndClose)

return () => {
window.removeEventListener('keydown', checkKeyAndClose)
}
}, [onClose])
return (
<div
className={styles.backdrop}
Expand Down
13 changes: 13 additions & 0 deletions webview/src/stories/Plots.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,16 @@ MultiviewZoomedInPlot.play = async ({ canvasElement }) => {

fireEvent.click(plotButton)
}

export const CheckpointZoomedInPlot = Template.bind({})
CheckpointZoomedInPlot.parameters = {
chromatic: { delay: 500 }
}
CheckpointZoomedInPlot.play = async ({ canvasElement }) => {
const canvas = within(canvasElement)
const plot = await canvas.findByText('summary.json:val_accuracy')

plot.scrollIntoView()

fireEvent.click(plot)
}

0 comments on commit 6138da2

Please sign in to comment.