Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Give Setup webview a single section #3448

Merged
merged 3 commits into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions extension/src/setup/webview/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,13 @@ export type SetupData = {
projectInitialized: boolean
pythonBinPath: string | undefined
}

export enum Section {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this enum name unique (as well as the one in plot)? Importing after typing only section might be confusing if the wrong Section is imported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually got hit by this already. I will update after #3452.

EXPERIMENTS = 'experiments'
}

export const DEFAULT_SECTION_COLLAPSED = {
[Section.EXPERIMENTS]: false
}

export type SectionCollapsed = typeof DEFAULT_SECTION_COLLAPSED
112 changes: 31 additions & 81 deletions webview/src/setup/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import { SetupData } from 'dvc/src/setup/webview/contract'
import {
MessageFromWebviewType,
MessageToWebview
} from 'dvc/src/webview/contract'
DEFAULT_SECTION_COLLAPSED,
Section,
SetupData
} from 'dvc/src/setup/webview/contract'
import { MessageToWebview } from 'dvc/src/webview/contract'
import React, { useCallback, useState } from 'react'
import { CliIncompatible } from './CliIncompatible'
import { CliUnavailable } from './CliUnavailable'
import { ProjectUninitialized } from './ProjectUninitialized'
import { NoData } from './NoData'
import { NeedsGitCommit } from './NeedsGitCommit'
import { SetupExperiments } from './Experiments'
import { SectionContainer } from '../../shared/components/sectionContainer/SectionContainer'
import { useVsCodeMessaging } from '../../shared/hooks/useVsCodeMessaging'
import { sendMessage } from '../../shared/vscode'
import { EmptyState } from '../../shared/components/emptyState/EmptyState'

// eslint-disable-next-line sonarjs/cognitive-complexity
export const App: React.FC = () => {
const [cliCompatible, setCliCompatible] = useState<boolean | undefined>(
undefined
Expand All @@ -32,6 +27,9 @@ export const App: React.FC = () => {
const [isPythonExtensionInstalled, setIsPythonExtensionInstalled] =
useState<boolean>(false)
const [hasData, setHasData] = useState<boolean | undefined>(false)
const [sectionCollapsed, setSectionCollapsed] = useState<
typeof DEFAULT_SECTION_COLLAPSED
>(DEFAULT_SECTION_COLLAPSED)

useVsCodeMessaging(
useCallback(
Expand All @@ -58,76 +56,28 @@ export const App: React.FC = () => {
)
)

const checkCompatibility = () => {
sendMessage({ type: MessageFromWebviewType.CHECK_CLI_COMPATIBLE })
}

const initializeGit = () => {
sendMessage({
type: MessageFromWebviewType.INITIALIZE_GIT
})
}

const initializeDvc = () => {
sendMessage({
type: MessageFromWebviewType.INITIALIZE_DVC
})
}

const showScmPanel = () => {
sendMessage({ type: MessageFromWebviewType.SHOW_SCM_PANEL })
}

const installDvc = () => {
sendMessage({ type: MessageFromWebviewType.INSTALL_DVC })
}

const selectPythonInterpreter = () => {
sendMessage({ type: MessageFromWebviewType.SELECT_PYTHON_INTERPRETER })
}

const setupWorkspace = () => {
sendMessage({ type: MessageFromWebviewType.SETUP_WORKSPACE })
}

if (cliCompatible === false) {
return <CliIncompatible checkCompatibility={checkCompatibility} />
}

if (cliCompatible === undefined) {
return (
<CliUnavailable
installDvc={installDvc}
isPythonExtensionInstalled={isPythonExtensionInstalled}
pythonBinPath={pythonBinPath}
selectPythonInterpreter={selectPythonInterpreter}
setupWorkspace={setupWorkspace}
/>
)
}

if (!projectInitialized) {
return (
<ProjectUninitialized
return (
<SectionContainer
sectionCollapsed={sectionCollapsed[Section.EXPERIMENTS]}
sectionKey={Section.EXPERIMENTS}
title={'Experiments'}
onToggleSection={() =>
setSectionCollapsed({
...sectionCollapsed,
[Section.EXPERIMENTS]: !sectionCollapsed[Section.EXPERIMENTS]
})
}
>
<SetupExperiments
canGitInitialize={canGitInitialize}
initializeDvc={initializeDvc}
initializeGit={initializeGit}
cliCompatible={cliCompatible}
hasData={hasData}
isPythonExtensionInstalled={isPythonExtensionInstalled}
needsGitInitialized={needsGitInitialized}
needsGitCommit={needsGitCommit}
projectInitialized={projectInitialized}
pythonBinPath={pythonBinPath}
/>
)
}

if (needsGitCommit) {
return <NeedsGitCommit showScmPanel={showScmPanel} />
}

if (hasData === undefined) {
return <EmptyState>Loading Project...</EmptyState>
}

if (!hasData) {
return <NoData />
}

return null
</SectionContainer>
)
}
80 changes: 80 additions & 0 deletions webview/src/setup/components/Experiments.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React from 'react'
import { CliIncompatible } from './CliIncompatible'
import { CliUnavailable } from './CliUnavailable'
import { ProjectUninitialized } from './ProjectUninitialized'
import {
checkCompatibility,
initializeDvc,
initializeGit,
installDvc,
selectPythonInterpreter,
setupWorkspace,
showScmPanel
} from './messages'
import { NeedsGitCommit } from './NeedsGitCommit'
import { NoData } from './NoData'
import { EmptyState } from '../../shared/components/emptyState/EmptyState'

export type SetupExperimentsProps = {
canGitInitialize: boolean | undefined
cliCompatible: boolean | undefined
hasData: boolean | undefined
isPythonExtensionInstalled: boolean
needsGitInitialized: boolean | undefined
needsGitCommit: boolean
projectInitialized: boolean
pythonBinPath: string | undefined
}

export const SetupExperiments: React.FC<SetupExperimentsProps> = ({
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function SetupExperiments has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring.

canGitInitialize,
cliCompatible,
hasData,
isPythonExtensionInstalled,
needsGitInitialized,
needsGitCommit,
projectInitialized,
pythonBinPath
// eslint-disable-next-line sonarjs/cognitive-complexity
}) => {
if (cliCompatible === false) {
return <CliIncompatible checkCompatibility={checkCompatibility} />
}

if (cliCompatible === undefined) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar blocks of code found in 2 locations. Consider refactoring.

return (
<CliUnavailable
installDvc={installDvc}
isPythonExtensionInstalled={isPythonExtensionInstalled}
pythonBinPath={pythonBinPath}
selectPythonInterpreter={selectPythonInterpreter}
setupWorkspace={setupWorkspace}
/>
)
}

if (!projectInitialized) {
return (
<ProjectUninitialized
canGitInitialize={canGitInitialize}
initializeDvc={initializeDvc}
initializeGit={initializeGit}
needsGitInitialized={needsGitInitialized}
/>
)
}

if (needsGitCommit) {
return <NeedsGitCommit showScmPanel={showScmPanel} />
}

if (hasData === undefined) {
return <EmptyState>Loading Project...</EmptyState>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this function.

}

if (!hasData) {
return <NoData />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this function.

}

return <EmptyState>{"You're all setup"}</EmptyState>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this function.

}
34 changes: 34 additions & 0 deletions webview/src/setup/components/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { MessageFromWebviewType } from 'dvc/src/webview/contract'
import { sendMessage } from '../../shared/vscode'

export const checkCompatibility = () => {
sendMessage({ type: MessageFromWebviewType.CHECK_CLI_COMPATIBLE })
}

export const initializeGit = () => {
sendMessage({
type: MessageFromWebviewType.INITIALIZE_GIT
})
}

export const initializeDvc = () => {
sendMessage({
type: MessageFromWebviewType.INITIALIZE_DVC
})
}

export const showScmPanel = () => {
sendMessage({ type: MessageFromWebviewType.SHOW_SCM_PANEL })
}

export const installDvc = () => {
sendMessage({ type: MessageFromWebviewType.INSTALL_DVC })
}

export const selectPythonInterpreter = () => {
sendMessage({ type: MessageFromWebviewType.SELECT_PYTHON_INTERPRETER })
}

export const setupWorkspace = () => {
sendMessage({ type: MessageFromWebviewType.SETUP_WORKSPACE })
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import cx from 'classnames'
import React, { MouseEvent } from 'react'
import { Section as PlotsSection } from 'dvc/src/plots/webview/contract'
import { Section as SetupSection } from 'dvc/src/setup/webview/contract'
import styles from './styles.module.scss'
import { Icon } from '../Icon'
import { ChevronDown, ChevronRight, Info } from '../icons'
Expand Down Expand Up @@ -55,12 +56,22 @@ export const SectionDescription = {
</a>
.
</span>
),
// Setup Experiments
[SetupSection.EXPERIMENTS]: (
<span data-testid="tooltip-setup-experiments">
Configure the extension to start tracking and visualizing{' '}
<a href="https://dvc.org/doc/start/experiment-management/experiments">
experiments
</a>
.
</span>
)
} as const

export interface SectionContainerProps<T extends PlotsSection> {
export interface SectionContainerProps<T extends PlotsSection | SetupSection> {
children: React.ReactNode
menuItems: IconMenuItemProps[]
menuItems?: IconMenuItemProps[]
onToggleSection: () => void
sectionCollapsed: boolean
sectionKey: T
Expand All @@ -73,10 +84,10 @@ const InfoIcon = () => (
)

export const SectionContainer: React.FC<
SectionContainerProps<PlotsSection>
SectionContainerProps<PlotsSection | SetupSection>
> = ({
children,
menuItems,
menuItems = [],
onToggleSection,
sectionCollapsed,
sectionKey,
Expand Down