From 83bd304b95f566fdd590a5439f3b80f0c60fde7c Mon Sep 17 00:00:00 2001 From: julieg18 Date: Fri, 14 Apr 2023 17:01:39 -0500 Subject: [PATCH 01/20] Pass dvc cli details the front end --- extension/src/setup/index.ts | 38 ++++- extension/src/setup/webview/contract.ts | 14 ++ extension/src/setup/webview/messages.ts | 2 + webview/src/setup/components/App.test.tsx | 165 +++++++++++++++++++++- webview/src/setup/components/App.tsx | 9 +- webview/src/setup/components/Dvc.tsx | 3 +- webview/src/stories/Setup.stories.tsx | 11 +- 7 files changed, 234 insertions(+), 8 deletions(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 7ff15ea986..7fd3f7929a 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -8,7 +8,12 @@ import { } from 'vscode' import { Disposable, Disposer } from '@hediet/std/disposable' import isEmpty from 'lodash.isempty' -import { SetupSection, SetupData as TSetupData } from './webview/contract' +import { + DvcCliDetails, + DvcCliIndicator, + SetupSection, + SetupData as TSetupData +} from './webview/contract' import { collectSectionCollapsed } from './collect' import { WebviewMessages } from './webview/messages' import { validateTokenInput } from './inputBox' @@ -84,6 +89,7 @@ export class Setup private cliAccessible = false private cliCompatible: boolean | undefined + private cliVersion: string | undefined private dotFolderWatcher?: Disposer @@ -334,6 +340,33 @@ export class Setup return this.sendDataToWebview() } + private async getEnvDetails(): Promise { + const dvcPath = this.config.getCliPath() + const pythonBinPath = this.config.getPythonBinPath() + let version + const cwd = getFirstWorkspaceFolder() + + if (cwd) { + version = await this.getCliVersion(cwd) + } + + if (dvcPath || !pythonBinPath) { + return { + location: dvcPath || 'dvc', + type: DvcCliIndicator.GLOBAL, + version + } + } + + return { + location: pythonBinPath, + type: this.config.isPythonExtensionUsed() + ? DvcCliIndicator.AUTO + : DvcCliIndicator.MANUAL, + version + } + } + private async sendDataToWebview() { const projectInitialized = this.hasRoots() const hasData = this.getHasData() @@ -348,9 +381,12 @@ export class Setup const pythonBinPath = await findPythonBinForInstall() + const dvcCliDetails = await this.getEnvDetails() + this.webviewMessages.sendWebviewMessage({ canGitInitialize, cliCompatible: this.cliCompatible, + dvcCliDetails, hasData, isPythonExtensionInstalled: isPythonExtensionInstalled(), isStudioConnected: this.studioIsConnected, diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index a3aa5df5ea..9fda828fe4 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -1,6 +1,20 @@ +export enum DvcCliIndicator { + AUTO = 'auto', + MANUAL = 'manual', + GLOBAL = 'global', + UNKNOWN = 'unknown' +} + +export type DvcCliDetails = { + location: string + type: DvcCliIndicator + version: string | undefined +} + export type SetupData = { canGitInitialize: boolean cliCompatible: boolean | undefined + dvcCliDetails: DvcCliDetails hasData: boolean | undefined isPythonExtensionInstalled: boolean isStudioConnected: boolean diff --git a/extension/src/setup/webview/messages.ts b/extension/src/setup/webview/messages.ts index b43d4597ee..7afdab1413 100644 --- a/extension/src/setup/webview/messages.ts +++ b/extension/src/setup/webview/messages.ts @@ -35,6 +35,7 @@ export class WebviewMessages { public sendWebviewMessage({ canGitInitialize, cliCompatible, + dvcCliDetails, hasData, isPythonExtensionInstalled, isStudioConnected, @@ -48,6 +49,7 @@ export class WebviewMessages { void this.getWebview()?.show({ canGitInitialize, cliCompatible, + dvcCliDetails, hasData, isPythonExtensionInstalled, isStudioConnected, diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 3784e95214..8063aa0450 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -5,7 +5,11 @@ import { } from 'dvc/src/webview/contract' import '@testing-library/jest-dom/extend-expect' import React from 'react' -import { SetupSection, SetupData } from 'dvc/src/setup/webview/contract' +import { + SetupSection, + SetupData, + DvcCliIndicator +} from 'dvc/src/setup/webview/contract' import { App } from './App' import { vsCodeApi } from '../../shared/api' @@ -66,6 +70,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: false, + dvcCliDetails: { + location: 'dvc', + type: DvcCliIndicator.GLOBAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -92,6 +101,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: undefined, + dvcCliDetails: { + location: 'dvc', + type: DvcCliIndicator.GLOBAL, + version: undefined + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -112,6 +126,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: undefined, + dvcCliDetails: { + location: 'dvc', + type: DvcCliIndicator.GLOBAL, + version: undefined + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -136,8 +155,13 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: undefined, + dvcCliDetails: { + location: defaultInterpreter, + type: DvcCliIndicator.AUTO, + version: undefined + }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionInstalled: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -159,6 +183,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: undefined, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: undefined + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -182,6 +211,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: undefined, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: undefined + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: false, @@ -205,6 +239,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: undefined, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: undefined + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: false, @@ -228,6 +267,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -248,6 +292,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -266,6 +315,11 @@ describe('App', () => { renderApp({ canGitInitialize: true, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -287,6 +341,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -305,6 +364,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -323,6 +387,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -343,6 +412,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -366,6 +440,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -389,6 +468,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: true, isPythonExtensionInstalled: true, isStudioConnected: true, @@ -414,6 +498,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -432,6 +521,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -456,7 +550,12 @@ describe('App', () => { it('should show a screen saying that dvc is not setup if the project is initalized but dvc is not installed', () => { renderApp({ canGitInitialize: false, - cliCompatible: true, + cliCompatible: false, + dvcCliDetails: { + location: 'dvc', + type: DvcCliIndicator.GLOBAL, + version: undefined + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -475,6 +574,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: true, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -495,6 +599,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -513,6 +622,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: undefined, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -531,6 +645,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -551,6 +670,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: true, isPythonExtensionInstalled: true, isStudioConnected: true, @@ -576,6 +700,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: false, @@ -596,6 +725,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: false, @@ -620,6 +754,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: false, @@ -644,6 +783,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: false, @@ -671,6 +815,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: true, @@ -695,6 +844,11 @@ describe('App', () => { renderApp({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: true, @@ -718,6 +872,11 @@ describe('App', () => { const testData = { canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, hasData: false, isPythonExtensionInstalled: true, isStudioConnected: true, diff --git a/webview/src/setup/components/App.tsx b/webview/src/setup/components/App.tsx index 460b7bf079..865e6481c6 100644 --- a/webview/src/setup/components/App.tsx +++ b/webview/src/setup/components/App.tsx @@ -1,7 +1,8 @@ import { DEFAULT_SECTION_COLLAPSED, SetupSection, - SetupData + SetupData, + DvcCliDetails } from 'dvc/src/setup/webview/contract' import { MessageFromWebviewType, @@ -19,6 +20,9 @@ export const App: React.FC = () => { const [cliCompatible, setCliCompatible] = useState( undefined ) + const [dvcCliDetails, setDvcCliDetails] = useState( + undefined + ) const [projectInitialized, setProjectInitialized] = useState(false) const [needsGitInitialized, setNeedsGitInitialized] = useState< boolean | undefined @@ -36,7 +40,6 @@ export const App: React.FC = () => { const [sectionCollapsed, setSectionCollapsed] = useState( DEFAULT_SECTION_COLLAPSED ) - const [isStudioConnected, setIsStudioConnected] = useState(false) const [shareLiveToStudio, setShareLiveToStudioValue] = useState(false) @@ -47,6 +50,7 @@ export const App: React.FC = () => { setCanGitInitialized(data.data.canGitInitialize) setCliCompatible(data.data.cliCompatible) setHasData(data.data.hasData) + setDvcCliDetails(data.data.dvcCliDetails) setIsPythonExtensionInstalled(data.data.isPythonExtensionInstalled) setNeedsGitInitialized(data.data.needsGitInitialized) setNeedsGitCommit(data.data.needsGitCommit) @@ -93,6 +97,7 @@ export const App: React.FC = () => { Date: Fri, 14 Apr 2023 17:48:49 -0500 Subject: [PATCH 02/20] Fix vscode tests --- extension/src/setup/index.ts | 2 +- extension/src/test/suite/setup/index.test.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 7fd3f7929a..9575892f93 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -340,7 +340,7 @@ export class Setup return this.sendDataToWebview() } - private async getEnvDetails(): Promise { + public async getEnvDetails(): Promise { const dvcPath = this.config.getCliPath() const pythonBinPath = this.config.getPythonBinPath() let version diff --git a/extension/src/test/suite/setup/index.test.ts b/extension/src/test/suite/setup/index.test.ts index ca9a3a215c..3e824fb5ed 100644 --- a/extension/src/test/suite/setup/index.test.ts +++ b/extension/src/test/suite/setup/index.test.ts @@ -218,6 +218,7 @@ suite('Setup Test Suite', () => { setup.setCliCompatible(undefined) setup.setAvailable(false) await setup.setRoots() + stub(setup, 'getCliVersion').resolves(undefined) messageSpy.restore() const mockSendMessage = stub(BaseWebview.prototype, 'show') @@ -238,6 +239,7 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: undefined, + dvcCliDetails: { location: 'dvc', type: 'global', version: undefined }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -278,6 +280,11 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: true, + dvcCliDetails: { + location: 'dvc', + type: 'global', + version: MIN_CLI_VERSION + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -324,6 +331,11 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'dvc', + type: 'global', + version: MIN_CLI_VERSION + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -370,6 +382,11 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: false, cliCompatible: true, + dvcCliDetails: { + location: 'dvc', + type: 'global', + version: MIN_CLI_VERSION + }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -568,6 +585,7 @@ suite('Setup Test Suite', () => { mockRunSetup.restore() stub(config, 'isPythonExtensionUsed').returns(false) stub(config, 'getPythonBinPath').resolves(join('python')) + stub(setup, 'getEnvDetails').resolves(undefined) mockVersion.resetBehavior() mockVersion @@ -627,6 +645,7 @@ suite('Setup Test Suite', () => { mockExecuteCommand.restore() mockRunSetup.restore() stub(config, 'isPythonExtensionUsed').returns(true) + stub(setup, 'getEnvDetails').resolves(undefined) mockVersion.resetBehavior() mockVersion.rejects(new Error('no CLI here')) From 395ac9b971244ffee41397023d7b8085fd9ce8cd Mon Sep 17 00:00:00 2001 From: julieg18 Date: Mon, 17 Apr 2023 08:45:37 -0500 Subject: [PATCH 03/20] wip for front end --- extension/src/test/suite/setup/util.ts | 4 ++- webview/src/setup/components/Dvc.tsx | 3 ++ .../src/setup/components/DvcEnvDetails.tsx | 31 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 webview/src/setup/components/DvcEnvDetails.tsx diff --git a/extension/src/test/suite/setup/util.ts b/extension/src/test/suite/setup/util.ts index ae95867b86..25dd21312c 100644 --- a/extension/src/test/suite/setup/util.ts +++ b/extension/src/test/suite/setup/util.ts @@ -100,7 +100,9 @@ export const buildSetup = ( getHasData: () => hasData, showWebview: mockOpenExperiments } as unknown as WorkspaceExperiments, - { setAvailability: stub() } as unknown as Status, + { + setAvailability: stub() + } as unknown as Status, resourceLocator.dvcIcon, new StopWatch(), () => Promise.resolve([undefined]), diff --git a/webview/src/setup/components/Dvc.tsx b/webview/src/setup/components/Dvc.tsx index f020364442..46cbfcaafc 100644 --- a/webview/src/setup/components/Dvc.tsx +++ b/webview/src/setup/components/Dvc.tsx @@ -1,5 +1,6 @@ import React from 'react' import { DvcCliDetails, SectionCollapsed } from 'dvc/src/setup/webview/contract' +import { DvcEnvDetails } from './DvcEnvDetails' import { CliIncompatible } from './CliIncompatible' import { CliUnavailable } from './CliUnavailable' import { ProjectUninitialized } from './ProjectUninitialized' @@ -32,6 +33,7 @@ export type DvcProps = { export const Dvc: React.FC = ({ canGitInitialize, cliCompatible, + dvcCliDetails, isPythonExtensionInstalled, needsGitInitialized, projectInitialized, @@ -84,6 +86,7 @@ export const Dvc: React.FC = ({ } text="Show Experiments" /> + {dvcCliDetails && } ) } diff --git a/webview/src/setup/components/DvcEnvDetails.tsx b/webview/src/setup/components/DvcEnvDetails.tsx new file mode 100644 index 0000000000..c5564d5c45 --- /dev/null +++ b/webview/src/setup/components/DvcEnvDetails.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' + +const getTextBasedOffType = ( + type: string, + location: string, + version: string | undefined +) => { + if (type === DvcCliIndicator.GLOBAL && version) { + return `The extension is using a global version of DVC at ${location}.` + } + + if (type === DvcCliIndicator.GLOBAL && !version) { + return "The extension can't find DVC." + } + + return `The extension is using python located at ${location}.` +} + +export const DvcEnvDetails: React.FC = ({ + location, + version, + type +}) => { + return ( +
+

DVC CLI Info

+

{getTextBasedOffType(type, location, version)}

+
+ ) +} From c680243e8333549bcd01754e37545c22bfb9ca00 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Mon, 17 Apr 2023 18:14:30 -0500 Subject: [PATCH 04/20] Add WIP frontend design --- extension/src/setup/webview/contract.ts | 3 +- webview/src/setup/components/App.tsx | 2 +- .../src/setup/components/DvcEnvDetails.tsx | 31 -------------- .../components/{ => dvc}/CliIncompatible.tsx | 4 +- .../components/{ => dvc}/CliUnavailable.tsx | 4 +- .../src/setup/components/{ => dvc}/Dvc.tsx | 11 +++-- .../setup/components/dvc/DvcEnvDetails.tsx | 40 +++++++++++++++++++ .../{ => dvc}/ProjectUninitialized.tsx | 4 +- .../setup/components/dvc/styles.module.scss | 29 ++++++++++++++ webview/src/shared/variables.scss | 3 ++ 10 files changed, 85 insertions(+), 46 deletions(-) delete mode 100644 webview/src/setup/components/DvcEnvDetails.tsx rename webview/src/setup/components/{ => dvc}/CliIncompatible.tsx (80%) rename webview/src/setup/components/{ => dvc}/CliUnavailable.tsx (93%) rename webview/src/setup/components/{ => dvc}/Dvc.tsx (91%) create mode 100644 webview/src/setup/components/dvc/DvcEnvDetails.tsx rename webview/src/setup/components/{ => dvc}/ProjectUninitialized.tsx (93%) create mode 100644 webview/src/setup/components/dvc/styles.module.scss diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index 9fda828fe4..742ac545e1 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -1,8 +1,7 @@ export enum DvcCliIndicator { AUTO = 'auto', MANUAL = 'manual', - GLOBAL = 'global', - UNKNOWN = 'unknown' + GLOBAL = 'global' } export type DvcCliDetails = { diff --git a/webview/src/setup/components/App.tsx b/webview/src/setup/components/App.tsx index 865e6481c6..383806403c 100644 --- a/webview/src/setup/components/App.tsx +++ b/webview/src/setup/components/App.tsx @@ -9,7 +9,7 @@ import { MessageToWebview } from 'dvc/src/webview/contract' import React, { useCallback, useState } from 'react' -import { Dvc } from './Dvc' +import { Dvc } from './dvc/Dvc' import { Experiments } from './Experiments' import { Studio } from './Studio' import { SetupContainer } from './SetupContainer' diff --git a/webview/src/setup/components/DvcEnvDetails.tsx b/webview/src/setup/components/DvcEnvDetails.tsx deleted file mode 100644 index c5564d5c45..0000000000 --- a/webview/src/setup/components/DvcEnvDetails.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' -import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' - -const getTextBasedOffType = ( - type: string, - location: string, - version: string | undefined -) => { - if (type === DvcCliIndicator.GLOBAL && version) { - return `The extension is using a global version of DVC at ${location}.` - } - - if (type === DvcCliIndicator.GLOBAL && !version) { - return "The extension can't find DVC." - } - - return `The extension is using python located at ${location}.` -} - -export const DvcEnvDetails: React.FC = ({ - location, - version, - type -}) => { - return ( -
-

DVC CLI Info

-

{getTextBasedOffType(type, location, version)}

-
- ) -} diff --git a/webview/src/setup/components/CliIncompatible.tsx b/webview/src/setup/components/dvc/CliIncompatible.tsx similarity index 80% rename from webview/src/setup/components/CliIncompatible.tsx rename to webview/src/setup/components/dvc/CliIncompatible.tsx index ae67b486a0..1c1fc35199 100644 --- a/webview/src/setup/components/CliIncompatible.tsx +++ b/webview/src/setup/components/dvc/CliIncompatible.tsx @@ -1,7 +1,7 @@ import React from 'react' import { MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' -import { EmptyState } from '../../shared/components/emptyState/EmptyState' -import { Button } from '../../shared/components/button/Button' +import { EmptyState } from '../../../shared/components/emptyState/EmptyState' +import { Button } from '../../../shared/components/button/Button' type CliIncompatibleProps = { checkCompatibility: () => void } diff --git a/webview/src/setup/components/CliUnavailable.tsx b/webview/src/setup/components/dvc/CliUnavailable.tsx similarity index 93% rename from webview/src/setup/components/CliUnavailable.tsx rename to webview/src/setup/components/dvc/CliUnavailable.tsx index 880c7aa93e..bb634c0d72 100644 --- a/webview/src/setup/components/CliUnavailable.tsx +++ b/webview/src/setup/components/dvc/CliUnavailable.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { Button } from '../../shared/components/button/Button' -import { EmptyState } from '../../shared/components/emptyState/EmptyState' +import { Button } from '../../../shared/components/button/Button' +import { EmptyState } from '../../../shared/components/emptyState/EmptyState' const Title: React.FC = () =>

DVC is currently unavailable

diff --git a/webview/src/setup/components/Dvc.tsx b/webview/src/setup/components/dvc/Dvc.tsx similarity index 91% rename from webview/src/setup/components/Dvc.tsx rename to webview/src/setup/components/dvc/Dvc.tsx index 46cbfcaafc..91ab18aa87 100644 --- a/webview/src/setup/components/Dvc.tsx +++ b/webview/src/setup/components/dvc/Dvc.tsx @@ -2,8 +2,8 @@ import React from 'react' import { DvcCliDetails, SectionCollapsed } from 'dvc/src/setup/webview/contract' import { DvcEnvDetails } from './DvcEnvDetails' import { CliIncompatible } from './CliIncompatible' -import { CliUnavailable } from './CliUnavailable' import { ProjectUninitialized } from './ProjectUninitialized' +import { CliUnavailable } from './CliUnavailable' import { checkCompatibility, initializeDvc, @@ -12,11 +12,10 @@ import { selectPythonInterpreter, setupWorkspace, showExperiments -} from './messages' - -import { EmptyState } from '../../shared/components/emptyState/EmptyState' -import { Beaker } from '../../shared/components/icons' -import { IconButton } from '../../shared/components/button/IconButton' +} from '../messages' +import { EmptyState } from '../../../shared/components/emptyState/EmptyState' +import { Beaker } from '../../../shared/components/icons' +import { IconButton } from '../../../shared/components/button/IconButton' export type DvcProps = { canGitInitialize: boolean | undefined diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx new file mode 100644 index 0000000000..5a90c33240 --- /dev/null +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' +import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' +import styles from './styles.module.scss' + +const getTextBasedOffType = (type: string, version: string | undefined) => { + if (type === DvcCliIndicator.GLOBAL && !version) { + return "The extension can't find DVC " + } + + if (type === DvcCliIndicator.GLOBAL) { + return 'The extension is using DVC installed globally ' + } + + return 'The extension is using DVC installed with Python ' +} + +export const DvcEnvDetails: React.FC = ({ + location, + version, + type +}) => { + return ( +
+

DVC CLI Info

+

+ {getTextBasedOffType(type, version)} + and requires a version between {MIN_CLI_VERSION} and {MAX_CLI_VERSION}. +

+

+ Location: {location} +

+ {version && ( +

+ Version: {version} +

+ )} +
+ ) +} diff --git a/webview/src/setup/components/ProjectUninitialized.tsx b/webview/src/setup/components/dvc/ProjectUninitialized.tsx similarity index 93% rename from webview/src/setup/components/ProjectUninitialized.tsx rename to webview/src/setup/components/dvc/ProjectUninitialized.tsx index 014282c67f..b84f212daf 100644 --- a/webview/src/setup/components/ProjectUninitialized.tsx +++ b/webview/src/setup/components/dvc/ProjectUninitialized.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { EmptyState } from '../../shared/components/emptyState/EmptyState' -import { Button } from '../../shared/components/button/Button' +import { EmptyState } from '../../../shared/components/emptyState/EmptyState' +import { Button } from '../../../shared/components/button/Button' const Header: React.FC = () =>

DVC is not initialized

diff --git a/webview/src/setup/components/dvc/styles.module.scss b/webview/src/setup/components/dvc/styles.module.scss new file mode 100644 index 0000000000..67caffd9fa --- /dev/null +++ b/webview/src/setup/components/dvc/styles.module.scss @@ -0,0 +1,29 @@ +@import '../../../shared/variables.scss'; + +.envDetails { + border: 1px solid $settings-border; + padding: 15px; + text-align: left; + font-size: 0.8125rem; + margin-top: 40px; + margin: 40px 20px 0; +} + +.title { + margin: 0; + font-size: 1rem; + color: $settings-header-foreground; +} + +.text { + margin: 0; + margin: 5px 0; +} + +.info { + margin: 0; + + > span { + font-weight: bold; + } +} diff --git a/webview/src/shared/variables.scss b/webview/src/shared/variables.scss index e6168c36e3..14fc7416b4 100644 --- a/webview/src/shared/variables.scss +++ b/webview/src/shared/variables.scss @@ -47,3 +47,6 @@ $plot-block-bg-color: var(--vscode-dropdown-background); $checkbox-background: var(--checkbox-background); $checkbox-border: var(--checkbox-border); + +$settings-border: var(--vscode-settings-headerBorder); +$settings-header-foreground: var(--vscode-settings-headerForeground); From c8431f416bc8e94921843f7a696f5a795a1e8f42 Mon Sep 17 00:00:00 2001 From: julieg18 Date: Mon, 17 Apr 2023 19:53:10 -0500 Subject: [PATCH 05/20] Add details as a constand and TODO LIST --- .../setup/components/dvc/CliIncompatible.tsx | 11 +++++-- .../setup/components/dvc/CliUnavailable.tsx | 8 +++-- webview/src/setup/components/dvc/Dvc.tsx | 19 ++++++++---- .../setup/components/dvc/DvcEnvDetails.tsx | 11 ++++++- .../components/dvc/ProjectUninitialized.tsx | 29 ++++++++++++++----- 5 files changed, 59 insertions(+), 19 deletions(-) diff --git a/webview/src/setup/components/dvc/CliIncompatible.tsx b/webview/src/setup/components/dvc/CliIncompatible.tsx index 1c1fc35199..d7dfb55dad 100644 --- a/webview/src/setup/components/dvc/CliIncompatible.tsx +++ b/webview/src/setup/components/dvc/CliIncompatible.tsx @@ -1,12 +1,16 @@ -import React from 'react' +import React, { ReactElement } from 'react' import { MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' import { Button } from '../../../shared/components/button/Button' -type CliIncompatibleProps = { checkCompatibility: () => void } +type CliIncompatibleProps = { + checkCompatibility: () => void + children: ReactElement +} export const CliIncompatible: React.FC = ({ - checkCompatibility + checkCompatibility, + children }) => (
@@ -15,6 +19,7 @@ export const CliIncompatible: React.FC = ({

The minimum version is {MIN_CLI_VERSION}.

Please update your install and try again.

) diff --git a/webview/src/setup/components/dvc/CliUnavailable.tsx b/webview/src/setup/components/dvc/CliUnavailable.tsx index bb634c0d72..96a8e04de4 100644 --- a/webview/src/setup/components/dvc/CliUnavailable.tsx +++ b/webview/src/setup/components/dvc/CliUnavailable.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { ReactElement } from 'react' import { Button } from '../../../shared/components/button/Button' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' @@ -10,6 +10,7 @@ export type CliUnavailableProps = { pythonBinPath: string | undefined selectPythonInterpreter: () => void setupWorkspace: () => void + children: ReactElement } const OfferToInstall: React.FC<{ @@ -40,7 +41,8 @@ export const CliUnavailable: React.FC = ({ isPythonExtensionInstalled, pythonBinPath, selectPythonInterpreter, - setupWorkspace + setupWorkspace, + children }) => { const SetupWorkspace: React.FC<{ description: string }> = ({ description @@ -60,6 +62,7 @@ export const CliUnavailable: React.FC = ({ <p>DVC & DVCLive cannot be auto-installed as Python was not located.</p> <SetupWorkspace description="To locate a Python Interpreter or DVC." /> + {children} </EmptyState> ) } @@ -78,6 +81,7 @@ export const CliUnavailable: React.FC<CliUnavailableProps> = ({ <SetupWorkspace description="To update the install location or locate DVC." /> )} </OfferToInstall> + {children} </EmptyState> ) } diff --git a/webview/src/setup/components/dvc/Dvc.tsx b/webview/src/setup/components/dvc/Dvc.tsx index 91ab18aa87..408821fff9 100644 --- a/webview/src/setup/components/dvc/Dvc.tsx +++ b/webview/src/setup/components/dvc/Dvc.tsx @@ -40,8 +40,14 @@ export const Dvc: React.FC<DvcProps> = ({ setSectionCollapsed, isExperimentsAvailable }) => { + const children = <>{dvcCliDetails && <DvcEnvDetails {...dvcCliDetails} />}</> + if (cliCompatible === false) { - return <CliIncompatible checkCompatibility={checkCompatibility} /> + return ( + <CliIncompatible checkCompatibility={checkCompatibility}> + {children} + </CliIncompatible> + ) } if (cliCompatible === undefined) { @@ -52,7 +58,9 @@ export const Dvc: React.FC<DvcProps> = ({ pythonBinPath={pythonBinPath} selectPythonInterpreter={selectPythonInterpreter} setupWorkspace={setupWorkspace} - /> + > + {children} + </CliUnavailable> ) } @@ -63,10 +71,11 @@ export const Dvc: React.FC<DvcProps> = ({ initializeDvc={initializeDvc} initializeGit={initializeGit} needsGitInitialized={needsGitInitialized} - /> + > + {children} + </ProjectUninitialized> ) } - return ( <EmptyState isFullScreen={false}> <h1>Setup Complete</h1> @@ -85,7 +94,7 @@ export const Dvc: React.FC<DvcProps> = ({ } text="Show Experiments" /> - {dvcCliDetails && <DvcEnvDetails {...dvcCliDetails} />} + {children} </EmptyState> ) } diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index 5a90c33240..15c4578fd1 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -3,8 +3,17 @@ import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import styles from './styles.module.scss' +// TBD this logic needs some improvement +// 1. that "and" statement about versioning doesn't make sense with all phrases. +// maybe just leave it as a separate sentence OR add it as an info block +// 2. The extension can't find DVC BUT will show currently selected location... +// rename to "Env Location", "Selected Env Location", "Env"? Or maybe hide +// entirely when things arent installed... +// 3. Text just needs better grammar as a whole probably +// 4. Text should mention if it's set with python extension or manually + const getTextBasedOffType = (type: string, version: string | undefined) => { - if (type === DvcCliIndicator.GLOBAL && !version) { + if (!version) { return "The extension can't find DVC " } diff --git a/webview/src/setup/components/dvc/ProjectUninitialized.tsx b/webview/src/setup/components/dvc/ProjectUninitialized.tsx index b84f212daf..0860ef8104 100644 --- a/webview/src/setup/components/dvc/ProjectUninitialized.tsx +++ b/webview/src/setup/components/dvc/ProjectUninitialized.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { ReactElement } from 'react' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' import { Button } from '../../../shared/components/button/Button' @@ -7,6 +7,7 @@ const Header: React.FC = () => <h1>DVC is not initialized</h1> interface GitUninitializedProps { canGitInitialize: boolean | undefined initializeGit: () => void + children: ReactElement } const GitIsPrerequisite: React.FC = () => ( @@ -15,7 +16,8 @@ const GitIsPrerequisite: React.FC = () => ( const GitUninitialized: React.FC<GitUninitializedProps> = ({ canGitInitialize, - initializeGit + initializeGit, + children }) => { if (!canGitInitialize) { return ( @@ -30,6 +32,7 @@ const GitUninitialized: React.FC<GitUninitializedProps> = ({ Please open a different folder which contains no Git repositories or a single existing Git repository at the root. </p> + {children} </EmptyState> ) } @@ -43,9 +46,10 @@ const GitUninitialized: React.FC<GitUninitializedProps> = ({ ) } -const DvcUninitialized: React.FC<{ initializeDvc: () => void }> = ({ - initializeDvc -}) => ( +const DvcUninitialized: React.FC<{ + initializeDvc: () => void + children: ReactElement +}> = ({ initializeDvc, children }) => ( <EmptyState isFullScreen={false}> <Header /> <p> @@ -54,6 +58,7 @@ const DvcUninitialized: React.FC<{ initializeDvc: () => void }> = ({ to use DVC please read <a href="https://dvc.org/doc">our docs</a>. </p> <Button onClick={initializeDvc} text="Initialize Project"></Button> + {children} </EmptyState> ) @@ -62,22 +67,30 @@ export interface ProjectUninitializedProps { initializeDvc: () => void initializeGit: () => void needsGitInitialized: boolean | undefined + children: ReactElement } export const ProjectUninitialized: React.FC<ProjectUninitializedProps> = ({ initializeDvc, needsGitInitialized, canGitInitialize, - initializeGit + initializeGit, + children }) => { if (needsGitInitialized) { return ( <GitUninitialized initializeGit={initializeGit} canGitInitialize={canGitInitialize} - /> + > + {children} + </GitUninitialized> ) } - return <DvcUninitialized initializeDvc={initializeDvc} /> + return ( + <DvcUninitialized initializeDvc={initializeDvc}> + {children} + </DvcUninitialized> + ) } From f55ad95053f350b1f2befa76d789336bb93fa2d2 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Tue, 18 Apr 2023 09:01:24 -0500 Subject: [PATCH 06/20] Resolve comments and clean up --- .../setup/components/dvc/DvcEnvDetails.tsx | 56 ++++++++++--------- .../components/dvc/ProjectUninitialized.tsx | 1 + .../setup/components/dvc/styles.module.scss | 8 ++- 3 files changed, 36 insertions(+), 29 deletions(-) diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index 15c4578fd1..fd9e01a880 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -3,27 +3,30 @@ import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import styles from './styles.module.scss' -// TBD this logic needs some improvement -// 1. that "and" statement about versioning doesn't make sense with all phrases. -// maybe just leave it as a separate sentence OR add it as an info block -// 2. The extension can't find DVC BUT will show currently selected location... -// rename to "Env Location", "Selected Env Location", "Env"? Or maybe hide -// entirely when things arent installed... -// 3. Text just needs better grammar as a whole probably -// 4. Text should mention if it's set with python extension or manually - const getTextBasedOffType = (type: string, version: string | undefined) => { if (!version) { - return "The extension can't find DVC " + return "The extension can't find DVC." } - if (type === DvcCliIndicator.GLOBAL) { - return 'The extension is using DVC installed globally ' + switch (type) { + case DvcCliIndicator.GLOBAL: + return 'The extension is using DVC installed within a global environment.' + case DvcCliIndicator.AUTO: + return 'The extension is using DVC installed within a python environment selected via the Python extension.' + case DvcCliIndicator.MANUAL: + return 'The extension is using DVC installed within a python environment selected manually.' } - - return 'The extension is using DVC installed with Python ' } +const InfoListItem: React.FC<{ title: string; text: string }> = ({ + title, + text +}) => ( + <li> + <span className={styles.bold}>{title}:</span> {text} + </li> +) + export const DvcEnvDetails: React.FC<DvcCliDetails> = ({ location, version, @@ -32,18 +35,19 @@ export const DvcEnvDetails: React.FC<DvcCliDetails> = ({ return ( <div className={styles.envDetails}> <h2 className={styles.title}>DVC CLI Info</h2> - <p className={styles.text}> - {getTextBasedOffType(type, version)} - and requires a version between {MIN_CLI_VERSION} and {MAX_CLI_VERSION}. - </p> - <p className={styles.info}> - <span>Location:</span> {location} - </p> - {version && ( - <p className={styles.info}> - <span>Version:</span> {version} - </p> - )} + <p className={styles.text}>{getTextBasedOffType(type, version)}</p> + <ul className={styles.info}> + {version && ( + <> + <InfoListItem title="Location" text={location} /> + <InfoListItem title="Version" text={version} /> + </> + )} + <InfoListItem + title="Required Version" + text={`${MIN_CLI_VERSION} - ${MAX_CLI_VERSION}`} + /> + </ul> </div> ) } diff --git a/webview/src/setup/components/dvc/ProjectUninitialized.tsx b/webview/src/setup/components/dvc/ProjectUninitialized.tsx index 0860ef8104..7915d4d3d8 100644 --- a/webview/src/setup/components/dvc/ProjectUninitialized.tsx +++ b/webview/src/setup/components/dvc/ProjectUninitialized.tsx @@ -42,6 +42,7 @@ const GitUninitialized: React.FC<GitUninitializedProps> = ({ <Header /> <GitIsPrerequisite /> <Button onClick={initializeGit} text="Initialize Git" /> + {children} </EmptyState> ) } diff --git a/webview/src/setup/components/dvc/styles.module.scss b/webview/src/setup/components/dvc/styles.module.scss index 67caffd9fa..5c4e3e0fa6 100644 --- a/webview/src/setup/components/dvc/styles.module.scss +++ b/webview/src/setup/components/dvc/styles.module.scss @@ -21,9 +21,11 @@ } .info { + padding: 0; margin: 0; + list-style: none; +} - > span { - font-weight: bold; - } +.bold { + font-weight: bold; } From c2afb03e63f64f56b935ed9c081b463769cb357b Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Tue, 18 Apr 2023 09:25:49 -0500 Subject: [PATCH 07/20] Add frontend tests --- webview/src/setup/components/App.test.tsx | 124 ++++++++++++++++++++++ webview/src/setup/components/App.tsx | 1 + 2 files changed, 125 insertions(+) diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 8063aa0450..08197fcbf8 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -22,6 +22,7 @@ const mockPostMessage = jest.mocked(postMessage) const renderApp = ({ canGitInitialize, cliCompatible, + dvcCliDetails, hasData, isPythonExtensionInstalled, isStudioConnected, @@ -40,6 +41,7 @@ const renderApp = ({ data: { canGitInitialize, cliCompatible, + dvcCliDetails, hasData, isPythonExtensionInstalled, isStudioConnected, @@ -491,6 +493,128 @@ describe('App', () => { type: MessageFromWebviewType.OPEN_EXPERIMENTS_WEBVIEW }) }) + + it('should show DVC CLI Info when DVC is unavailable', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: undefined, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: undefined + }, + hasData: false, + isPythonExtensionInstalled: true, + isStudioConnected: false, + needsGitCommit: false, + needsGitInitialized: undefined, + projectInitialized: false, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() + expect( + screen.getByText("The extension can't find DVC.") + ).toBeInTheDocument() + expect(screen.getByText('Required Version:')).toBeInTheDocument() + expect(screen.queryByText('Location:')).not.toBeInTheDocument() + expect(screen.queryByText('Version:')).not.toBeInTheDocument() + }) + + it('should show DVC CLI Info when DVC is set globally', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: undefined, + dvcCliDetails: { + location: 'dvc', + type: DvcCliIndicator.GLOBAL, + version: '1.0.0' + }, + hasData: false, + isPythonExtensionInstalled: true, + isStudioConnected: false, + needsGitCommit: false, + needsGitInitialized: undefined, + projectInitialized: false, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() + expect( + screen.getByText( + 'The extension is using DVC installed within a global environment.' + ) + ).toBeInTheDocument() + expect(screen.getByText('Required Version:')).toBeInTheDocument() + expect(screen.getByText('Location:')).toBeInTheDocument() + expect(screen.getByText('Version:')).toBeInTheDocument() + }) + + it('should show DVC CLI Info when DVC is set with the Python extension', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: undefined, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.AUTO, + version: '1.0.0' + }, + hasData: false, + isPythonExtensionInstalled: true, + isStudioConnected: false, + needsGitCommit: false, + needsGitInitialized: undefined, + projectInitialized: false, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() + expect( + screen.getByText( + 'The extension is using DVC installed within a python environment selected via the Python extension.' + ) + ).toBeInTheDocument() + expect(screen.getByText('Required Version:')).toBeInTheDocument() + expect(screen.getByText('Location:')).toBeInTheDocument() + expect(screen.getByText('Version:')).toBeInTheDocument() + }) + + it('should show DVC CLI Info when DVC is set manually', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: undefined, + dvcCliDetails: { + location: 'python', + type: DvcCliIndicator.MANUAL, + version: '1.0.0' + }, + hasData: false, + isPythonExtensionInstalled: true, + isStudioConnected: false, + needsGitCommit: false, + needsGitInitialized: undefined, + projectInitialized: false, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() + expect( + screen.getByText( + 'The extension is using DVC installed within a python environment selected manually.' + ) + ).toBeInTheDocument() + expect(screen.getByText('Required Version:')).toBeInTheDocument() + expect(screen.getByText('Location:')).toBeInTheDocument() + expect(screen.getByText('Version:')).toBeInTheDocument() + }) }) describe('Experiments', () => { diff --git a/webview/src/setup/components/App.tsx b/webview/src/setup/components/App.tsx index 383806403c..b65c7857e0 100644 --- a/webview/src/setup/components/App.tsx +++ b/webview/src/setup/components/App.tsx @@ -66,6 +66,7 @@ export const App: React.FC = () => { setCanGitInitialized, setCliCompatible, setHasData, + setDvcCliDetails, setIsPythonExtensionInstalled, setNeedsGitInitialized, setNeedsGitCommit, From 83265288922daa9fedb15e96a4524c79e81d9010 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Tue, 18 Apr 2023 10:11:35 -0500 Subject: [PATCH 08/20] Fix error being thrown in vscode tests --- extension/src/test/suite/setup/index.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extension/src/test/suite/setup/index.test.ts b/extension/src/test/suite/setup/index.test.ts index 3e824fb5ed..287af0c7b4 100644 --- a/extension/src/test/suite/setup/index.test.ts +++ b/extension/src/test/suite/setup/index.test.ts @@ -781,6 +781,7 @@ suite('Setup Test Suite', () => { const mockUpdate = stub() stub(workspace, 'getConfiguration').returns({ + get: stub(), update: mockUpdate } as unknown as WorkspaceConfiguration) From ddb69c42e4f08e6e2f5ab71a2475a35d95aa1f04 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Tue, 18 Apr 2023 10:46:02 -0500 Subject: [PATCH 09/20] cleanup --- extension/src/test/suite/setup/util.ts | 4 +--- webview/src/setup/components/App.test.tsx | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/extension/src/test/suite/setup/util.ts b/extension/src/test/suite/setup/util.ts index 25dd21312c..ae95867b86 100644 --- a/extension/src/test/suite/setup/util.ts +++ b/extension/src/test/suite/setup/util.ts @@ -100,9 +100,7 @@ export const buildSetup = ( getHasData: () => hasData, showWebview: mockOpenExperiments } as unknown as WorkspaceExperiments, - { - setAvailability: stub() - } as unknown as Status, + { setAvailability: stub() } as unknown as Status, resourceLocator.dvcIcon, new StopWatch(), () => Promise.resolve([undefined]), diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 08197fcbf8..786d7e4b73 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -163,7 +163,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionInstalled: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, From 3aba34640b29f7ae98f7b2c6721d3a2a40e9e69f Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Thu, 20 Apr 2023 16:40:05 -0500 Subject: [PATCH 10/20] new design --- webview/src/setup/components/App.test.tsx | 122 +----------------- .../setup/components/dvc/CliIncompatible.tsx | 4 +- .../setup/components/dvc/CliUnavailable.tsx | 4 +- webview/src/setup/components/dvc/Dvc.tsx | 2 +- .../setup/components/dvc/DvcEnvDetails.tsx | 50 +++---- .../components/dvc/ProjectUninitialized.tsx | 6 +- .../setup/components/dvc/styles.module.scss | 29 ++--- 7 files changed, 43 insertions(+), 174 deletions(-) diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 786d7e4b73..5353727191 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -494,127 +494,7 @@ describe('App', () => { }) }) - it('should show DVC CLI Info when DVC is unavailable', () => { - renderApp({ - canGitInitialize: false, - cliCompatible: undefined, - dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, - version: undefined - }, - hasData: false, - isPythonExtensionInstalled: true, - isStudioConnected: false, - needsGitCommit: false, - needsGitInitialized: undefined, - projectInitialized: false, - pythonBinPath: 'python', - sectionCollapsed: undefined, - shareLiveToStudio: false - }) - - expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() - expect( - screen.getByText("The extension can't find DVC.") - ).toBeInTheDocument() - expect(screen.getByText('Required Version:')).toBeInTheDocument() - expect(screen.queryByText('Location:')).not.toBeInTheDocument() - expect(screen.queryByText('Version:')).not.toBeInTheDocument() - }) - - it('should show DVC CLI Info when DVC is set globally', () => { - renderApp({ - canGitInitialize: false, - cliCompatible: undefined, - dvcCliDetails: { - location: 'dvc', - type: DvcCliIndicator.GLOBAL, - version: '1.0.0' - }, - hasData: false, - isPythonExtensionInstalled: true, - isStudioConnected: false, - needsGitCommit: false, - needsGitInitialized: undefined, - projectInitialized: false, - pythonBinPath: 'python', - sectionCollapsed: undefined, - shareLiveToStudio: false - }) - - expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() - expect( - screen.getByText( - 'The extension is using DVC installed within a global environment.' - ) - ).toBeInTheDocument() - expect(screen.getByText('Required Version:')).toBeInTheDocument() - expect(screen.getByText('Location:')).toBeInTheDocument() - expect(screen.getByText('Version:')).toBeInTheDocument() - }) - - it('should show DVC CLI Info when DVC is set with the Python extension', () => { - renderApp({ - canGitInitialize: false, - cliCompatible: undefined, - dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, - version: '1.0.0' - }, - hasData: false, - isPythonExtensionInstalled: true, - isStudioConnected: false, - needsGitCommit: false, - needsGitInitialized: undefined, - projectInitialized: false, - pythonBinPath: 'python', - sectionCollapsed: undefined, - shareLiveToStudio: false - }) - - expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() - expect( - screen.getByText( - 'The extension is using DVC installed within a python environment selected via the Python extension.' - ) - ).toBeInTheDocument() - expect(screen.getByText('Required Version:')).toBeInTheDocument() - expect(screen.getByText('Location:')).toBeInTheDocument() - expect(screen.getByText('Version:')).toBeInTheDocument() - }) - - it('should show DVC CLI Info when DVC is set manually', () => { - renderApp({ - canGitInitialize: false, - cliCompatible: undefined, - dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, - version: '1.0.0' - }, - hasData: false, - isPythonExtensionInstalled: true, - isStudioConnected: false, - needsGitCommit: false, - needsGitInitialized: undefined, - projectInitialized: false, - pythonBinPath: 'python', - sectionCollapsed: undefined, - shareLiveToStudio: false - }) - - expect(screen.getByText('DVC CLI Info')).toBeInTheDocument() - expect( - screen.getByText( - 'The extension is using DVC installed within a python environment selected manually.' - ) - ).toBeInTheDocument() - expect(screen.getByText('Required Version:')).toBeInTheDocument() - expect(screen.getByText('Location:')).toBeInTheDocument() - expect(screen.getByText('Version:')).toBeInTheDocument() - }) + // TBD add back tests when we have a more agreed upon solution }) describe('Experiments', () => { diff --git a/webview/src/setup/components/dvc/CliIncompatible.tsx b/webview/src/setup/components/dvc/CliIncompatible.tsx index d7dfb55dad..5df8c9f3b6 100644 --- a/webview/src/setup/components/dvc/CliIncompatible.tsx +++ b/webview/src/setup/components/dvc/CliIncompatible.tsx @@ -1,5 +1,4 @@ import React, { ReactElement } from 'react' -import { MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' import { Button } from '../../../shared/components/button/Button' @@ -15,11 +14,10 @@ export const CliIncompatible: React.FC<CliIncompatibleProps> = ({ <EmptyState isFullScreen={false}> <div> <h1>DVC is incompatible</h1> + {children} <p>The located CLI is incompatible with the extension.</p> - <p>The minimum version is {MIN_CLI_VERSION}.</p> <p>Please update your install and try again.</p> <Button text="Check Compatibility" onClick={checkCompatibility} /> - {children} </div> </EmptyState> ) diff --git a/webview/src/setup/components/dvc/CliUnavailable.tsx b/webview/src/setup/components/dvc/CliUnavailable.tsx index 96a8e04de4..bd62710102 100644 --- a/webview/src/setup/components/dvc/CliUnavailable.tsx +++ b/webview/src/setup/components/dvc/CliUnavailable.tsx @@ -60,9 +60,9 @@ export const CliUnavailable: React.FC<CliUnavailableProps> = ({ return ( <EmptyState isFullScreen={false}> <Title /> + {children} <p>DVC & DVCLive cannot be auto-installed as Python was not located.</p> <SetupWorkspace description="To locate a Python Interpreter or DVC." /> - {children} </EmptyState> ) } @@ -70,6 +70,7 @@ export const CliUnavailable: React.FC<CliUnavailableProps> = ({ return ( <EmptyState isFullScreen={false}> <Title /> + {children} <OfferToInstall pythonBinPath={pythonBinPath} installDvc={installDvc}> {isPythonExtensionInstalled ? ( <UpdateInterpreterOrFind @@ -81,7 +82,6 @@ export const CliUnavailable: React.FC<CliUnavailableProps> = ({ <SetupWorkspace description="To update the install location or locate DVC." /> )} </OfferToInstall> - {children} </EmptyState> ) } diff --git a/webview/src/setup/components/dvc/Dvc.tsx b/webview/src/setup/components/dvc/Dvc.tsx index 408821fff9..b1917debd9 100644 --- a/webview/src/setup/components/dvc/Dvc.tsx +++ b/webview/src/setup/components/dvc/Dvc.tsx @@ -79,6 +79,7 @@ export const Dvc: React.FC<DvcProps> = ({ return ( <EmptyState isFullScreen={false}> <h1>Setup Complete</h1> + {children} <IconButton appearance="primary" icon={Beaker} @@ -94,7 +95,6 @@ export const Dvc: React.FC<DvcProps> = ({ } text="Show Experiments" /> - {children} </EmptyState> ) } diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index fd9e01a880..dbee5fe259 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -3,28 +3,33 @@ import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import styles from './styles.module.scss' -const getTextBasedOffType = (type: string, version: string | undefined) => { +const getLocationValue = ( + location: string, + type: string, + version: string | undefined +): string | undefined => { if (!version) { - return "The extension can't find DVC." + return undefined } switch (type) { case DvcCliIndicator.GLOBAL: - return 'The extension is using DVC installed within a global environment.' + return `${location} (global)` case DvcCliIndicator.AUTO: - return 'The extension is using DVC installed within a python environment selected via the Python extension.' - case DvcCliIndicator.MANUAL: - return 'The extension is using DVC installed within a python environment selected manually.' + return `${location} (selected via python extension)` + default: + return `${location} (selected manually)` } } -const InfoListItem: React.FC<{ title: string; text: string }> = ({ +const InfoRow: React.FC<{ title: string; text: string | undefined }> = ({ title, text }) => ( - <li> - <span className={styles.bold}>{title}:</span> {text} - </li> + <tr> + <td className={styles.infoKey}>{title}</td> + <td className={styles.infoValue}>{text || 'Not found'}</td> + </tr> ) export const DvcEnvDetails: React.FC<DvcCliDetails> = ({ @@ -34,20 +39,17 @@ export const DvcEnvDetails: React.FC<DvcCliDetails> = ({ }) => { return ( <div className={styles.envDetails}> - <h2 className={styles.title}>DVC CLI Info</h2> - <p className={styles.text}>{getTextBasedOffType(type, version)}</p> - <ul className={styles.info}> - {version && ( - <> - <InfoListItem title="Location" text={location} /> - <InfoListItem title="Version" text={version} /> - </> - )} - <InfoListItem - title="Required Version" - text={`${MIN_CLI_VERSION} - ${MAX_CLI_VERSION}`} - /> - </ul> + <table className={styles.info}> + <tbody> + <InfoRow title="Min Required Version" text={MIN_CLI_VERSION} /> + <InfoRow title="Max Required Version" text={MAX_CLI_VERSION} /> + <InfoRow + title="Location" + text={getLocationValue(location, type, version)} + /> + <InfoRow title="Version" text={version} /> + </tbody> + </table> </div> ) } diff --git a/webview/src/setup/components/dvc/ProjectUninitialized.tsx b/webview/src/setup/components/dvc/ProjectUninitialized.tsx index 7915d4d3d8..1d1b27c34c 100644 --- a/webview/src/setup/components/dvc/ProjectUninitialized.tsx +++ b/webview/src/setup/components/dvc/ProjectUninitialized.tsx @@ -23,6 +23,7 @@ const GitUninitialized: React.FC<GitUninitializedProps> = ({ return ( <EmptyState isFullScreen={false}> <Header /> + {children} <GitIsPrerequisite /> <p> The extension is unable to initialize a Git repository in this @@ -32,7 +33,6 @@ const GitUninitialized: React.FC<GitUninitializedProps> = ({ Please open a different folder which contains no Git repositories or a single existing Git repository at the root. </p> - {children} </EmptyState> ) } @@ -40,9 +40,9 @@ const GitUninitialized: React.FC<GitUninitializedProps> = ({ return ( <EmptyState isFullScreen={false}> <Header /> + {children} <GitIsPrerequisite /> <Button onClick={initializeGit} text="Initialize Git" /> - {children} </EmptyState> ) } @@ -53,13 +53,13 @@ const DvcUninitialized: React.FC<{ }> = ({ initializeDvc, children }) => ( <EmptyState isFullScreen={false}> <Header /> + {children} <p> The current workspace does not contain a DVC project. You can initialize a project which will enable features powered by DVC. To learn more about how to use DVC please read <a href="https://dvc.org/doc">our docs</a>. </p> <Button onClick={initializeDvc} text="Initialize Project"></Button> - {children} </EmptyState> ) diff --git a/webview/src/setup/components/dvc/styles.module.scss b/webview/src/setup/components/dvc/styles.module.scss index 5c4e3e0fa6..46f06ae50b 100644 --- a/webview/src/setup/components/dvc/styles.module.scss +++ b/webview/src/setup/components/dvc/styles.module.scss @@ -1,31 +1,20 @@ @import '../../../shared/variables.scss'; .envDetails { - border: 1px solid $settings-border; - padding: 15px; text-align: left; - font-size: 0.8125rem; - margin-top: 40px; - margin: 40px 20px 0; + margin-bottom: 1rem; } -.title { - margin: 0; - font-size: 1rem; - color: $settings-header-foreground; +.infoKey, +.infoValue { + padding: 5px; } -.text { - margin: 0; - margin: 5px 0; -} - -.info { - padding: 0; - margin: 0; - list-style: none; +.infoKey { + font-weight: bold; + white-space: nowrap; } -.bold { - font-weight: bold; +.infoValue { + padding-left: 50px; } From 6a4f0927f9db6df2ba5453a4f8df0b1de24c95a1 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Fri, 21 Apr 2023 10:10:18 -0500 Subject: [PATCH 11/20] Adjust based off feedback --- extension/src/setup/index.ts | 13 ++--- extension/src/setup/webview/contract.ts | 5 +- .../setup/components/dvc/CliIncompatible.tsx | 1 - .../setup/components/dvc/DvcEnvDetails.tsx | 55 ++++++++----------- .../setup/components/dvc/styles.module.scss | 11 ++++ webview/src/stories/Setup.stories.tsx | 21 ++++--- 6 files changed, 55 insertions(+), 51 deletions(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 9575892f93..99bd1e0343 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -10,7 +10,6 @@ import { Disposable, Disposer } from '@hediet/std/disposable' import isEmpty from 'lodash.isempty' import { DvcCliDetails, - DvcCliIndicator, SetupSection, SetupData as TSetupData } from './webview/contract' @@ -352,17 +351,15 @@ export class Setup if (dvcPath || !pythonBinPath) { return { - location: dvcPath || 'dvc', - type: DvcCliIndicator.GLOBAL, + location: dvcPath ? 'dvc' : undefined, version } } - + // TBD if were going to keep this command logic we need to + // 1. possibly pull args from somewhere (see getOptions()) + // 2. rename location to command return { - location: pythonBinPath, - type: this.config.isPythonExtensionUsed() - ? DvcCliIndicator.AUTO - : DvcCliIndicator.MANUAL, + location: `${pythonBinPath} -m dvc`, version } } diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index 742ac545e1..dfc32e1725 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -5,8 +5,9 @@ export enum DvcCliIndicator { } export type DvcCliDetails = { - location: string - type: DvcCliIndicator + location: string | undefined + // TBD remove type entirely if we decide it's not useful + type?: DvcCliIndicator version: string | undefined } diff --git a/webview/src/setup/components/dvc/CliIncompatible.tsx b/webview/src/setup/components/dvc/CliIncompatible.tsx index 5df8c9f3b6..54adbdca05 100644 --- a/webview/src/setup/components/dvc/CliIncompatible.tsx +++ b/webview/src/setup/components/dvc/CliIncompatible.tsx @@ -15,7 +15,6 @@ export const CliIncompatible: React.FC<CliIncompatibleProps> = ({ <div> <h1>DVC is incompatible</h1> {children} - <p>The located CLI is incompatible with the extension.</p> <p>Please update your install and try again.</p> <Button text="Check Compatibility" onClick={checkCompatibility} /> </div> diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index dbee5fe259..441a1f9959 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -1,53 +1,42 @@ -import React from 'react' -import { DvcCliDetails, DvcCliIndicator } from 'dvc/src/setup/webview/contract' +import React, { ReactElement } from 'react' +import { DvcCliDetails } from 'dvc/src/setup/webview/contract' import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import styles from './styles.module.scss' +import { setupWorkspace } from '../messages' -const getLocationValue = ( - location: string, - type: string, - version: string | undefined -): string | undefined => { - if (!version) { - return undefined - } - - switch (type) { - case DvcCliIndicator.GLOBAL: - return `${location} (global)` - case DvcCliIndicator.AUTO: - return `${location} (selected via python extension)` - default: - return `${location} (selected manually)` - } -} - -const InfoRow: React.FC<{ title: string; text: string | undefined }> = ({ - title, - text -}) => ( +const InfoRow: React.FC<{ + title: string + text: string | ReactElement +}> = ({ title, text }) => ( <tr> <td className={styles.infoKey}>{title}</td> - <td className={styles.infoValue}>{text || 'Not found'}</td> + <td className={styles.infoValue}>{text}</td> </tr> ) export const DvcEnvDetails: React.FC<DvcCliDetails> = ({ location, - version, - type + version }) => { + const commandText = location || 'Not found' + const command = ( + <span> + <span className={styles.code}>{commandText}</span> ( + <button className={styles.buttonAsLink} onClick={setupWorkspace}> + Setup workspace + </button> + ) + </span> + ) + return ( <div className={styles.envDetails}> <table className={styles.info}> <tbody> <InfoRow title="Min Required Version" text={MIN_CLI_VERSION} /> <InfoRow title="Max Required Version" text={MAX_CLI_VERSION} /> - <InfoRow - title="Location" - text={getLocationValue(location, type, version)} - /> - <InfoRow title="Version" text={version} /> + <InfoRow title="Command" text={command} /> + <InfoRow title="Version" text={version || 'Not found'} /> </tbody> </table> </div> diff --git a/webview/src/setup/components/dvc/styles.module.scss b/webview/src/setup/components/dvc/styles.module.scss index 46f06ae50b..73ce09e8ad 100644 --- a/webview/src/setup/components/dvc/styles.module.scss +++ b/webview/src/setup/components/dvc/styles.module.scss @@ -1,4 +1,5 @@ @import '../../../shared/variables.scss'; +@import '../../../shared/mixins.scss'; .envDetails { text-align: left; @@ -18,3 +19,13 @@ .infoValue { padding-left: 50px; } + +.buttonAsLink { + @extend %link; + // TBD Move these into %buttonAsLink mixin? + background: none; + border: none; + padding: 0; + font-size: inherit; + cursor: pointer; +} diff --git a/webview/src/stories/Setup.stories.tsx b/webview/src/stories/Setup.stories.tsx index 51acfe7a52..8bd7c2b07d 100644 --- a/webview/src/stories/Setup.stories.tsx +++ b/webview/src/stories/Setup.stories.tsx @@ -1,11 +1,7 @@ import { Story, Meta } from '@storybook/react/types-6-0' import React from 'react' import { MessageToWebviewType } from 'dvc/src/webview/contract' -import { - DvcCliIndicator, - SetupData, - SetupSection -} from 'dvc/src/setup/webview/contract' +import { SetupData, SetupSection } from 'dvc/src/setup/webview/contract' import { DISABLE_CHROMATIC_SNAPSHOTS } from './util' import { App } from '../setup/components/App' @@ -13,8 +9,7 @@ const DEFAULT_DATA: SetupData = { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + location: 'path/to/python -m dvc', version: '1.0.0' }, hasData: false, @@ -81,6 +76,10 @@ CompletedConnected.args = getUpdatedArgs({ export const NoCLIPythonNotFound = Template.bind({}) NoCLIPythonNotFound.args = getUpdatedArgs({ cliCompatible: undefined, + dvcCliDetails: { + location: undefined, + version: undefined + }, isPythonExtensionInstalled: false, pythonBinPath: undefined }) @@ -88,6 +87,10 @@ NoCLIPythonNotFound.args = getUpdatedArgs({ export const NoCLIPythonExtensionUsed = Template.bind({}) NoCLIPythonExtensionUsed.args = getUpdatedArgs({ cliCompatible: undefined, + dvcCliDetails: { + location: '/opt/homebrew/Caskroom/miniforge/base/bin/python -m dvc', + version: undefined + }, isPythonExtensionInstalled: true, pythonBinPath: '/opt/homebrew/Caskroom/miniforge/base/bin/python' }) @@ -95,6 +98,10 @@ NoCLIPythonExtensionUsed.args = getUpdatedArgs({ export const NoCLIPythonExtensionNotUsed = Template.bind({}) NoCLIPythonExtensionNotUsed.args = getUpdatedArgs({ cliCompatible: undefined, + dvcCliDetails: { + location: '.env/bin/python -m dvc', + version: undefined + }, isPythonExtensionInstalled: false, pythonBinPath: '.env/bin/python' }) From 38764a5a16f403f9acd868180672b7a46d1a3d3b Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Mon, 24 Apr 2023 18:50:32 -0500 Subject: [PATCH 12/20] Clean up and add jest tests --- extension/src/setup/index.ts | 25 +- extension/src/setup/webview/contract.ts | 10 +- .../components/table/styles.module.scss | 6 +- webview/src/setup/components/App.test.tsx | 260 +++++++++++++----- .../setup/components/dvc/CliUnavailable.tsx | 76 ++--- webview/src/setup/components/dvc/Dvc.tsx | 14 +- .../setup/components/dvc/DvcEnvDetails.tsx | 64 +++-- .../setup/components/dvc/styles.module.scss | 31 ++- webview/src/shared/mixins.scss | 8 + webview/src/stories/Setup.stories.tsx | 8 +- 10 files changed, 312 insertions(+), 190 deletions(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 99bd1e0343..56e898bc48 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -56,6 +56,7 @@ import { GLOBAL_WEBVIEW_DVCROOT } from '../webview/factory' import { ConfigKey, getConfigValue } from '../vscode/config' import { getValidInput } from '../vscode/inputBox' import { Title } from '../vscode/title' +import { getOptions } from '../cli/dvc/options' export type SetupWebviewWebview = BaseWebview<TSetupData> @@ -339,11 +340,27 @@ export class Setup return this.sendDataToWebview() } + public getExampleCommand( + pythonBinPath: string | undefined, + dvcPath: string, + cwd: string + ) { + const { args, executable } = getOptions(pythonBinPath, dvcPath, cwd) + const commandArgs = args.join(' ').length === 0 ? '' : ` ${args.join(' ')}` + const command = executable + commandArgs + return command + commandArgs + } + public async getEnvDetails(): Promise<DvcCliDetails> { const dvcPath = this.config.getCliPath() const pythonBinPath = this.config.getPythonBinPath() let version const cwd = getFirstWorkspaceFolder() + const exampleCommand = this.getExampleCommand( + pythonBinPath, + dvcPath, + cwd || '' + ) if (cwd) { version = await this.getCliVersion(cwd) @@ -351,15 +368,13 @@ export class Setup if (dvcPath || !pythonBinPath) { return { - location: dvcPath ? 'dvc' : undefined, + exampleCommand: dvcPath ? exampleCommand : undefined, version } } - // TBD if were going to keep this command logic we need to - // 1. possibly pull args from somewhere (see getOptions()) - // 2. rename location to command + return { - location: `${pythonBinPath} -m dvc`, + exampleCommand, version } } diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index dfc32e1725..3e08bb7e2c 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -1,13 +1,5 @@ -export enum DvcCliIndicator { - AUTO = 'auto', - MANUAL = 'manual', - GLOBAL = 'global' -} - export type DvcCliDetails = { - location: string | undefined - // TBD remove type entirely if we decide it's not useful - type?: DvcCliIndicator + exampleCommand: string | undefined version: string | undefined } diff --git a/webview/src/experiments/components/table/styles.module.scss b/webview/src/experiments/components/table/styles.module.scss index a49f63ac55..d84082afbd 100644 --- a/webview/src/experiments/components/table/styles.module.scss +++ b/webview/src/experiments/components/table/styles.module.scss @@ -857,12 +857,8 @@ $badge-size: 0.85rem; } .buttonAsLink { - @extend %link; - background: none; - border: none; - padding: 0; + @extend %buttonAsLink; font-size: 0.65rem; - cursor: pointer; } .addConfigButton { diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 5353727191..5e4a496982 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -3,13 +3,10 @@ import { MessageFromWebviewType, MessageToWebviewType } from 'dvc/src/webview/contract' +import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import '@testing-library/jest-dom/extend-expect' import React from 'react' -import { - SetupSection, - SetupData, - DvcCliIndicator -} from 'dvc/src/setup/webview/contract' +import { SetupSection, SetupData } from 'dvc/src/setup/webview/contract' import { App } from './App' import { vsCodeApi } from '../../shared/api' @@ -73,8 +70,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: false, dvcCliDetails: { - location: 'dvc', - type: DvcCliIndicator.GLOBAL, + exampleCommand: 'dvc', version: '1.0.0' }, hasData: false, @@ -104,8 +100,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - location: 'dvc', - type: DvcCliIndicator.GLOBAL, + exampleCommand: 'dvc', version: undefined }, hasData: false, @@ -129,8 +124,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - location: 'dvc', - type: DvcCliIndicator.GLOBAL, + exampleCommand: 'dvc', version: undefined }, hasData: false, @@ -158,8 +152,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - location: defaultInterpreter, - type: DvcCliIndicator.AUTO, + exampleCommand: `${defaultInterpreter} -m dvc`, version: undefined }, hasData: false, @@ -186,8 +179,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: undefined }, hasData: false, @@ -201,7 +193,7 @@ describe('App', () => { shareLiveToStudio: false }) - const button = screen.getByText('Setup The Workspace') + const button = screen.getByText('Configure') fireEvent.click(button) expect(mockPostMessage).toHaveBeenCalledWith({ @@ -214,8 +206,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: undefined }, hasData: false, @@ -229,11 +220,11 @@ describe('App', () => { shareLiveToStudio: false }) - const button = screen.getByText('Select Python Interpreter') + const button = screen.getByText('Configure') fireEvent.click(button) expect(mockPostMessage).toHaveBeenCalledWith({ - type: MessageFromWebviewType.SELECT_PYTHON_INTERPRETER + type: MessageFromWebviewType.SETUP_WORKSPACE }) }) @@ -242,8 +233,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: undefined }, hasData: false, @@ -270,8 +260,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -295,8 +284,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -318,8 +306,7 @@ describe('App', () => { canGitInitialize: true, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -344,8 +331,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -367,8 +353,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -390,8 +375,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -415,8 +399,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -443,8 +426,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -471,8 +453,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -494,7 +475,159 @@ describe('App', () => { }) }) - // TBD add back tests when we have a more agreed upon solution + it('should show the user the version if dvc is installed', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: true, + dvcCliDetails: { + exampleCommand: 'python -m dvc', + version: '1.0.0' + }, + hasData: true, + isPythonExtensionInstalled: true, + isStudioConnected: true, + needsGitCommit: false, + needsGitInitialized: false, + projectInitialized: true, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + const envDetails = screen.getByTestId('dvc-env-details') + const exampleCommand = `1.0.0 (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + + expect(within(envDetails).getByText('Version')).toBeInTheDocument() + expect(within(envDetails).getByText(exampleCommand)).toBeInTheDocument() + }) + + it('should tell the user that version is not found if dvc is not installed', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: false, + dvcCliDetails: { + exampleCommand: 'dvc', + version: undefined + }, + hasData: false, + isPythonExtensionInstalled: false, + isStudioConnected: false, + needsGitCommit: false, + needsGitInitialized: undefined, + projectInitialized: false, + pythonBinPath: undefined, + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + const envDetails = screen.getByTestId('dvc-env-details') + const exampleCommand = `Not found (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + + expect(within(envDetails).getByText('Version')).toBeInTheDocument() + expect(within(envDetails).getByText(exampleCommand)).toBeInTheDocument() + }) + + it('should show the user an example command if dvc is installed', () => { + const exampleCommand = 'python -m dvc' + renderApp({ + canGitInitialize: false, + cliCompatible: true, + dvcCliDetails: { + exampleCommand, + version: '1.0.0' + }, + hasData: true, + isPythonExtensionInstalled: true, + isStudioConnected: true, + needsGitCommit: false, + needsGitInitialized: false, + projectInitialized: true, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + const envDetails = screen.getByTestId('dvc-env-details') + + expect(within(envDetails).getByText('Command')).toBeInTheDocument() + expect(within(envDetails).getByText(exampleCommand)).toBeInTheDocument() + }) + + it('should show user an example command with a "Configure" button if dvc is installed without the python extension', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: true, + dvcCliDetails: { + exampleCommand: 'dvc', + version: '1.0.0' + }, + hasData: true, + isPythonExtensionInstalled: false, + isStudioConnected: true, + needsGitCommit: false, + needsGitInitialized: false, + projectInitialized: true, + pythonBinPath: undefined, + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + const envDetails = screen.getByTestId('dvc-env-details') + + expect(within(envDetails).getByText('Command')).toBeInTheDocument() + + const configureButton = within(envDetails).getByText('Configure') + + expect(configureButton).toBeInTheDocument() + expect( + within(envDetails).queryByText('Select Python Interpreter') + ).not.toBeInTheDocument() + + fireEvent.click(configureButton) + + expect(mockPostMessage).toHaveBeenCalledWith({ + type: MessageFromWebviewType.SETUP_WORKSPACE + }) + }) + + it('should show user an example command with "Configure" and "Select Python Interpreter" buttons if dvc is installed with the python extension', () => { + renderApp({ + canGitInitialize: false, + cliCompatible: true, + dvcCliDetails: { + exampleCommand: 'python -m dvc', + version: '1.0.0' + }, + hasData: true, + isPythonExtensionInstalled: true, + isStudioConnected: true, + needsGitCommit: false, + needsGitInitialized: false, + projectInitialized: true, + pythonBinPath: 'python', + sectionCollapsed: undefined, + shareLiveToStudio: false + }) + + const envDetails = screen.getByTestId('dvc-env-details') + + expect(within(envDetails).getByText('Command')).toBeInTheDocument() + + const configureButton = within(envDetails).getByText('Configure') + const selectButton = within(envDetails).getByText( + 'Select Python Interpreter' + ) + + expect(configureButton).toBeInTheDocument() + expect(selectButton).toBeInTheDocument() + + mockPostMessage.mockClear() + + fireEvent.click(selectButton) + + expect(mockPostMessage).toHaveBeenCalledWith({ + type: MessageFromWebviewType.SELECT_PYTHON_INTERPRETER + }) + }) }) describe('Experiments', () => { @@ -503,8 +636,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -526,8 +658,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -556,8 +687,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: false, dvcCliDetails: { - location: 'dvc', - type: DvcCliIndicator.GLOBAL, + exampleCommand: 'dvc', version: undefined }, hasData: false, @@ -579,8 +709,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -604,8 +733,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -627,8 +755,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: undefined, @@ -650,8 +777,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.MANUAL, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -675,8 +801,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -705,8 +830,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -730,8 +854,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -759,8 +882,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -788,8 +910,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -820,8 +941,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -849,8 +969,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -877,8 +996,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'python', - type: DvcCliIndicator.AUTO, + exampleCommand: 'python -m dvc', version: '1.0.0' }, hasData: false, diff --git a/webview/src/setup/components/dvc/CliUnavailable.tsx b/webview/src/setup/components/dvc/CliUnavailable.tsx index bd62710102..27f025985f 100644 --- a/webview/src/setup/components/dvc/CliUnavailable.tsx +++ b/webview/src/setup/components/dvc/CliUnavailable.tsx @@ -1,4 +1,5 @@ import React, { ReactElement } from 'react' +import styles from './styles.module.scss' import { Button } from '../../../shared/components/button/Button' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' @@ -6,82 +7,41 @@ const Title: React.FC = () => <h1>DVC is currently unavailable</h1> export type CliUnavailableProps = { installDvc: () => void - isPythonExtensionInstalled: boolean pythonBinPath: string | undefined - selectPythonInterpreter: () => void setupWorkspace: () => void children: ReactElement } -const OfferToInstall: React.FC<{ - children: React.ReactNode - pythonBinPath: string - installDvc: () => void -}> = ({ installDvc, pythonBinPath, children }) => ( - <div> - <p>DVC & DVCLive can be auto-installed as packages with {pythonBinPath}</p> - <Button onClick={installDvc} text="Install" /> - {children} - </div> -) - -const UpdateInterpreterOrFind: React.FC<{ - action: string - description: string - onClick: () => void -}> = ({ action, description, onClick }) => ( - <div> - <p>{description}</p> - <Button onClick={onClick} text={action} /> - </div> -) - export const CliUnavailable: React.FC<CliUnavailableProps> = ({ installDvc, - isPythonExtensionInstalled, pythonBinPath, - selectPythonInterpreter, setupWorkspace, children }) => { - const SetupWorkspace: React.FC<{ description: string }> = ({ - description - }) => ( - <UpdateInterpreterOrFind - description={description} - action="Setup The Workspace" - onClick={setupWorkspace} - /> - ) - const canInstall = !!pythonBinPath - if (!canInstall) { - return ( - <EmptyState isFullScreen={false}> - <Title /> - {children} - <p>DVC & DVCLive cannot be auto-installed as Python was not located.</p> - <SetupWorkspace description="To locate a Python Interpreter or DVC." /> - </EmptyState> - ) - } + const contents = canInstall ? ( + <> + <p> + DVC & DVCLive can be auto-installed as packages with {pythonBinPath} + </p> + <div className={styles.sideBySideButtons}> + <Button onClick={installDvc} text="Install" /> + <Button onClick={setupWorkspace} text="Configure" /> + </div> + </> + ) : ( + <> + <p>DVC & DVCLive cannot be auto-installed as Python was not located.</p> + <Button onClick={setupWorkspace} text="Configure" /> + </> + ) return ( <EmptyState isFullScreen={false}> <Title /> {children} - <OfferToInstall pythonBinPath={pythonBinPath} installDvc={installDvc}> - {isPythonExtensionInstalled ? ( - <UpdateInterpreterOrFind - action="Select Python Interpreter" - description="To update the interpreter and/or locate DVC." - onClick={selectPythonInterpreter} - /> - ) : ( - <SetupWorkspace description="To update the install location or locate DVC." /> - )} - </OfferToInstall> + {contents} </EmptyState> ) } diff --git a/webview/src/setup/components/dvc/Dvc.tsx b/webview/src/setup/components/dvc/Dvc.tsx index b1917debd9..f35fba81f1 100644 --- a/webview/src/setup/components/dvc/Dvc.tsx +++ b/webview/src/setup/components/dvc/Dvc.tsx @@ -9,7 +9,6 @@ import { initializeDvc, initializeGit, installDvc, - selectPythonInterpreter, setupWorkspace, showExperiments } from '../messages' @@ -40,7 +39,16 @@ export const Dvc: React.FC<DvcProps> = ({ setSectionCollapsed, isExperimentsAvailable }) => { - const children = <>{dvcCliDetails && <DvcEnvDetails {...dvcCliDetails} />}</> + const children = ( + <> + {dvcCliDetails && ( + <DvcEnvDetails + {...dvcCliDetails} + isPythonExtensionInstalled={isPythonExtensionInstalled} + /> + )} + </> + ) if (cliCompatible === false) { return ( @@ -54,9 +62,7 @@ export const Dvc: React.FC<DvcProps> = ({ return ( <CliUnavailable installDvc={installDvc} - isPythonExtensionInstalled={isPythonExtensionInstalled} pythonBinPath={pythonBinPath} - selectPythonInterpreter={selectPythonInterpreter} setupWorkspace={setupWorkspace} > {children} diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index 441a1f9959..57736d53c2 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -2,43 +2,59 @@ import React, { ReactElement } from 'react' import { DvcCliDetails } from 'dvc/src/setup/webview/contract' import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' import styles from './styles.module.scss' -import { setupWorkspace } from '../messages' +import { selectPythonInterpreter, setupWorkspace } from '../messages' const InfoRow: React.FC<{ title: string text: string | ReactElement }> = ({ title, text }) => ( <tr> - <td className={styles.infoKey}>{title}</td> - <td className={styles.infoValue}>{text}</td> + <td className={styles.envDetailsKey}>{title}</td> + <td className={styles.envDetailsValue}>{text}</td> </tr> ) -export const DvcEnvDetails: React.FC<DvcCliDetails> = ({ - location, - version +interface DvcEnvDetailsProps extends DvcCliDetails { + isPythonExtensionInstalled: boolean +} + +export const DvcEnvDetails: React.FC<DvcEnvDetailsProps> = ({ + exampleCommand, + version, + isPythonExtensionInstalled }) => { - const commandText = location || 'Not found' + const versionText = `${ + version || 'Not found' + } (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + const commandText = exampleCommand || 'Not found' const command = ( - <span> - <span className={styles.code}>{commandText}</span> ( - <button className={styles.buttonAsLink} onClick={setupWorkspace}> - Setup workspace - </button> - ) - </span> + <> + <span className={styles.command}>{commandText}</span> + <span className={styles.actions}> + <button className={styles.buttonAsLink} onClick={setupWorkspace}> + Configure + </button> + {isPythonExtensionInstalled && ( + <> + <span className={styles.separator} /> + <button + className={styles.buttonAsLink} + onClick={selectPythonInterpreter} + > + Select Python Interpreter + </button> + </> + )} + </span> + </> ) return ( - <div className={styles.envDetails}> - <table className={styles.info}> - <tbody> - <InfoRow title="Min Required Version" text={MIN_CLI_VERSION} /> - <InfoRow title="Max Required Version" text={MAX_CLI_VERSION} /> - <InfoRow title="Command" text={command} /> - <InfoRow title="Version" text={version || 'Not found'} /> - </tbody> - </table> - </div> + <table data-testid="dvc-env-details" className={styles.envDetails}> + <tbody> + {version && <InfoRow title="Command" text={command} />} + <InfoRow title="Version" text={versionText} /> + </tbody> + </table> ) } diff --git a/webview/src/setup/components/dvc/styles.module.scss b/webview/src/setup/components/dvc/styles.module.scss index 73ce09e8ad..15e4f5ec06 100644 --- a/webview/src/setup/components/dvc/styles.module.scss +++ b/webview/src/setup/components/dvc/styles.module.scss @@ -2,30 +2,41 @@ @import '../../../shared/mixins.scss'; .envDetails { + margin: 0 auto; text-align: left; margin-bottom: 1rem; } -.infoKey, -.infoValue { +.envDetailsKey, +.envDetailsValue { padding: 5px; } -.infoKey { +.envDetailsKey { font-weight: bold; white-space: nowrap; + vertical-align: top; } -.infoValue { +.envDetailsValue { padding-left: 50px; + display: flex; + flex-direction: column; +} + +.separator { + margin: 0 5px; + + &::before { + content: '|'; + } } .buttonAsLink { - @extend %link; - // TBD Move these into %buttonAsLink mixin? - background: none; - border: none; - padding: 0; + @extend %buttonAsLink; font-size: inherit; - cursor: pointer; +} + +.sideBySideButtons > *:not(:first-child) { + margin-left: 15px; } diff --git a/webview/src/shared/mixins.scss b/webview/src/shared/mixins.scss index 5c6ce52440..712b3a06a3 100644 --- a/webview/src/shared/mixins.scss +++ b/webview/src/shared/mixins.scss @@ -9,3 +9,11 @@ color: var(--vscode-textLink-activeForeground); } } + +%buttonAsLink { + @extend %link; + background: none; + border: none; + padding: 0; + cursor: pointer; +} diff --git a/webview/src/stories/Setup.stories.tsx b/webview/src/stories/Setup.stories.tsx index 8bd7c2b07d..e50b42ee21 100644 --- a/webview/src/stories/Setup.stories.tsx +++ b/webview/src/stories/Setup.stories.tsx @@ -9,7 +9,7 @@ const DEFAULT_DATA: SetupData = { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'path/to/python -m dvc', + exampleCommand: 'path/to/python -m dvc', version: '1.0.0' }, hasData: false, @@ -77,7 +77,7 @@ export const NoCLIPythonNotFound = Template.bind({}) NoCLIPythonNotFound.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - location: undefined, + exampleCommand: undefined, version: undefined }, isPythonExtensionInstalled: false, @@ -88,7 +88,7 @@ export const NoCLIPythonExtensionUsed = Template.bind({}) NoCLIPythonExtensionUsed.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - location: '/opt/homebrew/Caskroom/miniforge/base/bin/python -m dvc', + exampleCommand: '/opt/homebrew/Caskroom/miniforge/base/bin/python -m dvc', version: undefined }, isPythonExtensionInstalled: true, @@ -99,7 +99,7 @@ export const NoCLIPythonExtensionNotUsed = Template.bind({}) NoCLIPythonExtensionNotUsed.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - location: '.env/bin/python -m dvc', + exampleCommand: '.env/bin/python -m dvc', version: undefined }, isPythonExtensionInstalled: false, From 48eb1eaaf72e8a50b3ffc79f6b778c17d4ba9060 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Tue, 25 Apr 2023 08:24:22 -0500 Subject: [PATCH 13/20] Fix vscode tests --- extension/src/setup/index.ts | 33 +++----------------- extension/src/setup/webview/contract.ts | 2 +- extension/src/test/suite/setup/index.test.ts | 14 +++------ webview/src/stories/Setup.stories.tsx | 2 +- 4 files changed, 10 insertions(+), 41 deletions(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 56e898bc48..101c36eeb5 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -89,7 +89,6 @@ export class Setup private cliAccessible = false private cliCompatible: boolean | undefined - private cliVersion: string | undefined private dotFolderWatcher?: Disposer @@ -340,42 +339,18 @@ export class Setup return this.sendDataToWebview() } - public getExampleCommand( - pythonBinPath: string | undefined, - dvcPath: string, - cwd: string - ) { - const { args, executable } = getOptions(pythonBinPath, dvcPath, cwd) - const commandArgs = args.join(' ').length === 0 ? '' : ` ${args.join(' ')}` - const command = executable + commandArgs - return command + commandArgs - } - public async getEnvDetails(): Promise<DvcCliDetails> { const dvcPath = this.config.getCliPath() const pythonBinPath = this.config.getPythonBinPath() - let version const cwd = getFirstWorkspaceFolder() - const exampleCommand = this.getExampleCommand( - pythonBinPath, - dvcPath, - cwd || '' - ) - if (cwd) { - version = await this.getCliVersion(cwd) - } - - if (dvcPath || !pythonBinPath) { - return { - exampleCommand: dvcPath ? exampleCommand : undefined, - version - } - } + const { args, executable } = getOptions(pythonBinPath, dvcPath, cwd || '') + const commandArgs = args.join(' ').length === 0 ? '' : ` ${args.join(' ')}` + const exampleCommand = executable + commandArgs return { exampleCommand, - version + version: cwd ? await this.getCliVersion(cwd) : undefined } } diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index 3e08bb7e2c..24919b0862 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -1,5 +1,5 @@ export type DvcCliDetails = { - exampleCommand: string | undefined + exampleCommand: string version: string | undefined } diff --git a/extension/src/test/suite/setup/index.test.ts b/extension/src/test/suite/setup/index.test.ts index 287af0c7b4..e68f5e7f6c 100644 --- a/extension/src/test/suite/setup/index.test.ts +++ b/extension/src/test/suite/setup/index.test.ts @@ -239,7 +239,7 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: undefined, - dvcCliDetails: { location: 'dvc', type: 'global', version: undefined }, + dvcCliDetails: { exampleCommand: 'dvc', version: undefined }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -280,11 +280,7 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: true, - dvcCliDetails: { - location: 'dvc', - type: 'global', - version: MIN_CLI_VERSION - }, + dvcCliDetails: { exampleCommand: 'dvc', version: '2.55.0' }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -332,8 +328,7 @@ suite('Setup Test Suite', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'dvc', - type: 'global', + exampleCommand: 'dvc', version: MIN_CLI_VERSION }, hasData: false, @@ -383,8 +378,7 @@ suite('Setup Test Suite', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - location: 'dvc', - type: 'global', + exampleCommand: 'dvc', version: MIN_CLI_VERSION }, hasData: false, diff --git a/webview/src/stories/Setup.stories.tsx b/webview/src/stories/Setup.stories.tsx index e50b42ee21..c92c2c962b 100644 --- a/webview/src/stories/Setup.stories.tsx +++ b/webview/src/stories/Setup.stories.tsx @@ -77,7 +77,7 @@ export const NoCLIPythonNotFound = Template.bind({}) NoCLIPythonNotFound.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - exampleCommand: undefined, + exampleCommand: 'dvc', version: undefined }, isPythonExtensionInstalled: false, From 1fdda0e2e003f65dd7407e6eb587b6801fc2b686 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Tue, 25 Apr 2023 08:47:44 -0500 Subject: [PATCH 14/20] Cleanup after reviewing code --- extension/src/test/suite/setup/index.test.ts | 2 +- webview/src/setup/components/App.test.tsx | 7 ++++--- webview/src/shared/variables.scss | 3 --- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/extension/src/test/suite/setup/index.test.ts b/extension/src/test/suite/setup/index.test.ts index e68f5e7f6c..5879a5d4e4 100644 --- a/extension/src/test/suite/setup/index.test.ts +++ b/extension/src/test/suite/setup/index.test.ts @@ -280,7 +280,7 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: true, - dvcCliDetails: { exampleCommand: 'dvc', version: '2.55.0' }, + dvcCliDetails: { exampleCommand: 'dvc', version: MIN_CLI_VERSION }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 5e4a496982..b2948d313b 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -576,11 +576,12 @@ describe('App', () => { expect(within(envDetails).getByText('Command')).toBeInTheDocument() const configureButton = within(envDetails).getByText('Configure') + const selectButton = within(envDetails).queryByText( + 'Select Python Interpreter' + ) expect(configureButton).toBeInTheDocument() - expect( - within(envDetails).queryByText('Select Python Interpreter') - ).not.toBeInTheDocument() + expect(selectButton).not.toBeInTheDocument() fireEvent.click(configureButton) diff --git a/webview/src/shared/variables.scss b/webview/src/shared/variables.scss index 14fc7416b4..e6168c36e3 100644 --- a/webview/src/shared/variables.scss +++ b/webview/src/shared/variables.scss @@ -47,6 +47,3 @@ $plot-block-bg-color: var(--vscode-dropdown-background); $checkbox-background: var(--checkbox-background); $checkbox-border: var(--checkbox-border); - -$settings-border: var(--vscode-settings-headerBorder); -$settings-header-foreground: var(--vscode-settings-headerForeground); From 12f850061f2f971426b416bd9a9ceb55da643859 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Wed, 26 Apr 2023 10:47:27 -0500 Subject: [PATCH 15/20] Break up components and use PropsWithChildren --- .../setup/components/dvc/CliIncompatible.tsx | 10 ++- .../setup/components/dvc/CliUnavailable.tsx | 16 ++--- webview/src/setup/components/dvc/Dvc.tsx | 14 ++-- .../setup/components/dvc/DvcEnvCommandRow.tsx | 39 ++++++++++ .../setup/components/dvc/DvcEnvDetails.tsx | 46 +++--------- .../setup/components/dvc/DvcEnvInfoRow.tsx | 12 ++++ .../setup/components/dvc/DvcUnitialized.tsx | 20 ++++++ .../setup/components/dvc/GitUnitialized.tsx | 36 ++++++++++ .../components/dvc/ProjectUninitialized.tsx | 72 ++----------------- 9 files changed, 137 insertions(+), 128 deletions(-) create mode 100644 webview/src/setup/components/dvc/DvcEnvCommandRow.tsx create mode 100644 webview/src/setup/components/dvc/DvcEnvInfoRow.tsx create mode 100644 webview/src/setup/components/dvc/DvcUnitialized.tsx create mode 100644 webview/src/setup/components/dvc/GitUnitialized.tsx diff --git a/webview/src/setup/components/dvc/CliIncompatible.tsx b/webview/src/setup/components/dvc/CliIncompatible.tsx index 54adbdca05..2bb441dc9e 100644 --- a/webview/src/setup/components/dvc/CliIncompatible.tsx +++ b/webview/src/setup/components/dvc/CliIncompatible.tsx @@ -1,16 +1,14 @@ -import React, { ReactElement } from 'react' +import React, { PropsWithChildren } from 'react' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' import { Button } from '../../../shared/components/button/Button' type CliIncompatibleProps = { checkCompatibility: () => void - children: ReactElement } -export const CliIncompatible: React.FC<CliIncompatibleProps> = ({ - checkCompatibility, - children -}) => ( +export const CliIncompatible: React.FC< + PropsWithChildren<CliIncompatibleProps> +> = ({ checkCompatibility, children }) => ( <EmptyState isFullScreen={false}> <div> <h1>DVC is incompatible</h1> diff --git a/webview/src/setup/components/dvc/CliUnavailable.tsx b/webview/src/setup/components/dvc/CliUnavailable.tsx index 27f025985f..fa9b7ad303 100644 --- a/webview/src/setup/components/dvc/CliUnavailable.tsx +++ b/webview/src/setup/components/dvc/CliUnavailable.tsx @@ -1,23 +1,17 @@ -import React, { ReactElement } from 'react' +import React, { PropsWithChildren } from 'react' import styles from './styles.module.scss' import { Button } from '../../../shared/components/button/Button' import { EmptyState } from '../../../shared/components/emptyState/EmptyState' -const Title: React.FC = () => <h1>DVC is currently unavailable</h1> - export type CliUnavailableProps = { installDvc: () => void pythonBinPath: string | undefined setupWorkspace: () => void - children: ReactElement } -export const CliUnavailable: React.FC<CliUnavailableProps> = ({ - installDvc, - pythonBinPath, - setupWorkspace, - children -}) => { +export const CliUnavailable: React.FC< + PropsWithChildren<CliUnavailableProps> +> = ({ installDvc, pythonBinPath, setupWorkspace, children }) => { const canInstall = !!pythonBinPath const contents = canInstall ? ( @@ -39,7 +33,7 @@ export const CliUnavailable: React.FC<CliUnavailableProps> = ({ return ( <EmptyState isFullScreen={false}> - <Title /> + <h1>DVC is currently unavailable</h1> {children} {contents} </EmptyState> diff --git a/webview/src/setup/components/dvc/Dvc.tsx b/webview/src/setup/components/dvc/Dvc.tsx index f35fba81f1..410b7a526c 100644 --- a/webview/src/setup/components/dvc/Dvc.tsx +++ b/webview/src/setup/components/dvc/Dvc.tsx @@ -39,15 +39,11 @@ export const Dvc: React.FC<DvcProps> = ({ setSectionCollapsed, isExperimentsAvailable }) => { - const children = ( - <> - {dvcCliDetails && ( - <DvcEnvDetails - {...dvcCliDetails} - isPythonExtensionInstalled={isPythonExtensionInstalled} - /> - )} - </> + const children = dvcCliDetails && ( + <DvcEnvDetails + {...dvcCliDetails} + isPythonExtensionInstalled={isPythonExtensionInstalled} + /> ) if (cliCompatible === false) { diff --git a/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx b/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx new file mode 100644 index 0000000000..d3291b1234 --- /dev/null +++ b/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx @@ -0,0 +1,39 @@ +import React from 'react' +import { DvcEnvInfoRow } from './DvcEnvInfoRow' +import styles from './styles.module.scss' +import { selectPythonInterpreter, setupWorkspace } from '../messages' + +interface DvcEnvCommandRowProps { + exampleCommand: string + isPythonExtensionInstalled: boolean +} + +export const DvcEnvCommandRow: React.FC<DvcEnvCommandRowProps> = ({ + exampleCommand, + isPythonExtensionInstalled +}) => { + const commandText = exampleCommand || 'Not found' + const command = ( + <> + <span className={styles.command}>{commandText}</span> + <span className={styles.actions}> + <button className={styles.buttonAsLink} onClick={setupWorkspace}> + Configure + </button> + {isPythonExtensionInstalled && ( + <> + <span className={styles.separator} /> + <button + className={styles.buttonAsLink} + onClick={selectPythonInterpreter} + > + Select Python Interpreter + </button> + </> + )} + </span> + </> + ) + + return <DvcEnvInfoRow title="Command" text={command} /> +} diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index 57736d53c2..ab6546aeeb 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -1,18 +1,9 @@ -import React, { ReactElement } from 'react' +import React from 'react' import { DvcCliDetails } from 'dvc/src/setup/webview/contract' import { MAX_CLI_VERSION, MIN_CLI_VERSION } from 'dvc/src/cli/dvc/contract' +import { DvcEnvInfoRow } from './DvcEnvInfoRow' import styles from './styles.module.scss' -import { selectPythonInterpreter, setupWorkspace } from '../messages' - -const InfoRow: React.FC<{ - title: string - text: string | ReactElement -}> = ({ title, text }) => ( - <tr> - <td className={styles.envDetailsKey}>{title}</td> - <td className={styles.envDetailsValue}>{text}</td> - </tr> -) +import { DvcEnvCommandRow } from './DvcEnvCommandRow' interface DvcEnvDetailsProps extends DvcCliDetails { isPythonExtensionInstalled: boolean @@ -26,34 +17,17 @@ export const DvcEnvDetails: React.FC<DvcEnvDetailsProps> = ({ const versionText = `${ version || 'Not found' } (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` - const commandText = exampleCommand || 'Not found' - const command = ( - <> - <span className={styles.command}>{commandText}</span> - <span className={styles.actions}> - <button className={styles.buttonAsLink} onClick={setupWorkspace}> - Configure - </button> - {isPythonExtensionInstalled && ( - <> - <span className={styles.separator} /> - <button - className={styles.buttonAsLink} - onClick={selectPythonInterpreter} - > - Select Python Interpreter - </button> - </> - )} - </span> - </> - ) return ( <table data-testid="dvc-env-details" className={styles.envDetails}> <tbody> - {version && <InfoRow title="Command" text={command} />} - <InfoRow title="Version" text={versionText} /> + {version && ( + <DvcEnvCommandRow + exampleCommand={exampleCommand} + isPythonExtensionInstalled={isPythonExtensionInstalled} + /> + )} + <DvcEnvInfoRow title="Version" text={versionText} /> </tbody> </table> ) diff --git a/webview/src/setup/components/dvc/DvcEnvInfoRow.tsx b/webview/src/setup/components/dvc/DvcEnvInfoRow.tsx new file mode 100644 index 0000000000..deecc1b761 --- /dev/null +++ b/webview/src/setup/components/dvc/DvcEnvInfoRow.tsx @@ -0,0 +1,12 @@ +import React, { ReactElement } from 'react' +import styles from './styles.module.scss' + +export const DvcEnvInfoRow: React.FC<{ + title: string + text: string | ReactElement +}> = ({ title, text }) => ( + <tr> + <td className={styles.envDetailsKey}>{title}</td> + <td className={styles.envDetailsValue}>{text}</td> + </tr> +) diff --git a/webview/src/setup/components/dvc/DvcUnitialized.tsx b/webview/src/setup/components/dvc/DvcUnitialized.tsx new file mode 100644 index 0000000000..02f0fee866 --- /dev/null +++ b/webview/src/setup/components/dvc/DvcUnitialized.tsx @@ -0,0 +1,20 @@ +import React, { PropsWithChildren } from 'react' +import { EmptyState } from '../../../shared/components/emptyState/EmptyState' +import { Button } from '../../../shared/components/button/Button' + +export const DvcUninitialized: React.FC< + PropsWithChildren<{ + initializeDvc: () => void + }> +> = ({ initializeDvc, children }) => ( + <EmptyState isFullScreen={false}> + <h1>DVC is not initialized</h1> + {children} + <p> + The current workspace does not contain a DVC project. You can initialize a + project which will enable features powered by DVC. To learn more about how + to use DVC please read <a href="https://dvc.org/doc">our docs</a>. + </p> + <Button onClick={initializeDvc} text="Initialize Project"></Button> + </EmptyState> +) diff --git a/webview/src/setup/components/dvc/GitUnitialized.tsx b/webview/src/setup/components/dvc/GitUnitialized.tsx new file mode 100644 index 0000000000..50bfc7465e --- /dev/null +++ b/webview/src/setup/components/dvc/GitUnitialized.tsx @@ -0,0 +1,36 @@ +import React, { PropsWithChildren } from 'react' +import { EmptyState } from '../../../shared/components/emptyState/EmptyState' +import { Button } from '../../../shared/components/button/Button' + +interface GitUninitializedProps { + canGitInitialize: boolean | undefined + initializeGit: () => void +} + +export const GitUninitialized: React.FC< + PropsWithChildren<GitUninitializedProps> +> = ({ canGitInitialize, initializeGit, children }) => { + const conditionalContent = canGitInitialize ? ( + <Button onClick={initializeGit} text="Initialize Git" /> + ) : ( + <> + <p> + The extension is unable to initialize a Git repository in this + workspace. + </p> + <p> + Please open a different folder which contains no Git repositories or a + single existing Git repository at the root. + </p> + </> + ) + + return ( + <EmptyState isFullScreen={false}> + <h1>DVC is not initialized</h1> + {children} + <p>A Git repository is a prerequisite of project initialization.</p> + {conditionalContent} + </EmptyState> + ) +} diff --git a/webview/src/setup/components/dvc/ProjectUninitialized.tsx b/webview/src/setup/components/dvc/ProjectUninitialized.tsx index 1d1b27c34c..2af828dda3 100644 --- a/webview/src/setup/components/dvc/ProjectUninitialized.tsx +++ b/webview/src/setup/components/dvc/ProjectUninitialized.tsx @@ -1,77 +1,17 @@ -import React, { ReactElement } from 'react' -import { EmptyState } from '../../../shared/components/emptyState/EmptyState' -import { Button } from '../../../shared/components/button/Button' - -const Header: React.FC = () => <h1>DVC is not initialized</h1> - -interface GitUninitializedProps { - canGitInitialize: boolean | undefined - initializeGit: () => void - children: ReactElement -} - -const GitIsPrerequisite: React.FC = () => ( - <p>A Git repository is a prerequisite of project initialization.</p> -) - -const GitUninitialized: React.FC<GitUninitializedProps> = ({ - canGitInitialize, - initializeGit, - children -}) => { - if (!canGitInitialize) { - return ( - <EmptyState isFullScreen={false}> - <Header /> - {children} - <GitIsPrerequisite /> - <p> - The extension is unable to initialize a Git repository in this - workspace. - </p> - <p> - Please open a different folder which contains no Git repositories or a - single existing Git repository at the root. - </p> - </EmptyState> - ) - } - - return ( - <EmptyState isFullScreen={false}> - <Header /> - {children} - <GitIsPrerequisite /> - <Button onClick={initializeGit} text="Initialize Git" /> - </EmptyState> - ) -} - -const DvcUninitialized: React.FC<{ - initializeDvc: () => void - children: ReactElement -}> = ({ initializeDvc, children }) => ( - <EmptyState isFullScreen={false}> - <Header /> - {children} - <p> - The current workspace does not contain a DVC project. You can initialize a - project which will enable features powered by DVC. To learn more about how - to use DVC please read <a href="https://dvc.org/doc">our docs</a>. - </p> - <Button onClick={initializeDvc} text="Initialize Project"></Button> - </EmptyState> -) +import React, { PropsWithChildren } from 'react' +import { GitUninitialized } from './GitUnitialized' +import { DvcUninitialized } from './DvcUnitialized' export interface ProjectUninitializedProps { canGitInitialize: boolean | undefined initializeDvc: () => void initializeGit: () => void needsGitInitialized: boolean | undefined - children: ReactElement } -export const ProjectUninitialized: React.FC<ProjectUninitializedProps> = ({ +export const ProjectUninitialized: React.FC< + PropsWithChildren<ProjectUninitializedProps> +> = ({ initializeDvc, needsGitInitialized, canGitInitialize, From 074d7969c53c6b07ad53325212b395466afaab93 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Wed, 26 Apr 2023 10:59:11 -0500 Subject: [PATCH 16/20] Fix typo and bugs --- webview/src/setup/components/App.test.tsx | 2 +- webview/src/stories/Setup.stories.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index b2948d313b..fddd88d261 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -279,7 +279,7 @@ describe('App', () => { ).not.toBeInTheDocument() }) - it('should not show a screen saying that DVC is not initialized if the project is not initialized and git is uninitialized', () => { + it('should show a screen saying that DVC is not initialized if the project is not initialized and git is uninitialized', () => { renderApp({ canGitInitialize: false, cliCompatible: true, diff --git a/webview/src/stories/Setup.stories.tsx b/webview/src/stories/Setup.stories.tsx index c92c2c962b..1076f81eae 100644 --- a/webview/src/stories/Setup.stories.tsx +++ b/webview/src/stories/Setup.stories.tsx @@ -114,17 +114,20 @@ CliFoundButNotCompatible.args = getUpdatedArgs({ export const CannotInitializeGit = Template.bind({}) CannotInitializeGit.args = getUpdatedArgs({ canGitInitialize: false, - needsGitInitialized: true + needsGitInitialized: true, + projectInitialized: false }) export const CanInitializeGit = Template.bind({}) CanInitializeGit.args = getUpdatedArgs({ canGitInitialize: true, - needsGitInitialized: true + needsGitInitialized: true, + projectInitialized: false }) export const DvcUninitialized = Template.bind({}) DvcUninitialized.args = getUpdatedArgs({ canGitInitialize: undefined, - needsGitInitialized: undefined + needsGitInitialized: undefined, + projectInitialized: false }) From 165f3e99ccaac72a17e9198418e61e5c6121df25 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Wed, 26 Apr 2023 11:09:30 -0500 Subject: [PATCH 17/20] Fix bug --- extension/src/setup/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 101c36eeb5..11c180ed13 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -345,7 +345,7 @@ export class Setup const cwd = getFirstWorkspaceFolder() const { args, executable } = getOptions(pythonBinPath, dvcPath, cwd || '') - const commandArgs = args.join(' ').length === 0 ? '' : ` ${args.join(' ')}` + const commandArgs = args.length === 0 ? '' : ` ${args.join(' ')}` const exampleCommand = executable + commandArgs return { From 212c8a4402d5ce72f22b7fba7f99c1634fa0f0c4 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Wed, 26 Apr 2023 11:10:31 -0500 Subject: [PATCH 18/20] Commit missed file --- webview/src/setup/components/dvc/styles.module.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webview/src/setup/components/dvc/styles.module.scss b/webview/src/setup/components/dvc/styles.module.scss index 15e4f5ec06..971a1c2a5c 100644 --- a/webview/src/setup/components/dvc/styles.module.scss +++ b/webview/src/setup/components/dvc/styles.module.scss @@ -1,5 +1,5 @@ -@import '../../../shared/variables.scss'; -@import '../../../shared/mixins.scss'; +@import '../../../shared/variables'; +@import '../../../shared/mixins'; .envDetails { margin: 0 auto; @@ -34,6 +34,7 @@ .buttonAsLink { @extend %buttonAsLink; + font-size: inherit; } From a05091b8fb7bd2af100bd9d9ad934780a0d939d3 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Wed, 26 Apr 2023 11:49:40 -0500 Subject: [PATCH 19/20] Renaming stuff --- extension/src/setup/index.ts | 8 +- extension/src/setup/webview/contract.ts | 2 +- extension/src/test/suite/setup/index.test.ts | 12 +-- webview/src/setup/components/App.test.tsx | 84 +++++++++---------- .../setup/components/dvc/DvcEnvCommandRow.tsx | 10 +-- .../setup/components/dvc/DvcEnvDetails.tsx | 4 +- webview/src/stories/Setup.stories.tsx | 8 +- 7 files changed, 64 insertions(+), 64 deletions(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index 11c180ed13..e55a35d5ca 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -339,17 +339,17 @@ export class Setup return this.sendDataToWebview() } - public async getEnvDetails(): Promise<DvcCliDetails> { + public async getDvcCliDetails(): Promise<DvcCliDetails> { const dvcPath = this.config.getCliPath() const pythonBinPath = this.config.getPythonBinPath() const cwd = getFirstWorkspaceFolder() const { args, executable } = getOptions(pythonBinPath, dvcPath, cwd || '') const commandArgs = args.length === 0 ? '' : ` ${args.join(' ')}` - const exampleCommand = executable + commandArgs + const command = executable + commandArgs return { - exampleCommand, + command, version: cwd ? await this.getCliVersion(cwd) : undefined } } @@ -368,7 +368,7 @@ export class Setup const pythonBinPath = await findPythonBinForInstall() - const dvcCliDetails = await this.getEnvDetails() + const dvcCliDetails = await this.getDvcCliDetails() this.webviewMessages.sendWebviewMessage({ canGitInitialize, diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index 24919b0862..37f6368837 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -1,5 +1,5 @@ export type DvcCliDetails = { - exampleCommand: string + command: string version: string | undefined } diff --git a/extension/src/test/suite/setup/index.test.ts b/extension/src/test/suite/setup/index.test.ts index 5879a5d4e4..b4f40a76a0 100644 --- a/extension/src/test/suite/setup/index.test.ts +++ b/extension/src/test/suite/setup/index.test.ts @@ -239,7 +239,7 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: undefined, - dvcCliDetails: { exampleCommand: 'dvc', version: undefined }, + dvcCliDetails: { command: 'dvc', version: undefined }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -280,7 +280,7 @@ suite('Setup Test Suite', () => { expect(mockSendMessage).to.be.calledWithExactly({ canGitInitialize: true, cliCompatible: true, - dvcCliDetails: { exampleCommand: 'dvc', version: MIN_CLI_VERSION }, + dvcCliDetails: { command: 'dvc', version: MIN_CLI_VERSION }, hasData: false, isPythonExtensionInstalled: false, isStudioConnected: false, @@ -328,7 +328,7 @@ suite('Setup Test Suite', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: MIN_CLI_VERSION }, hasData: false, @@ -378,7 +378,7 @@ suite('Setup Test Suite', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: MIN_CLI_VERSION }, hasData: false, @@ -579,7 +579,7 @@ suite('Setup Test Suite', () => { mockRunSetup.restore() stub(config, 'isPythonExtensionUsed').returns(false) stub(config, 'getPythonBinPath').resolves(join('python')) - stub(setup, 'getEnvDetails').resolves(undefined) + stub(setup, 'getDvcCliDetails').resolves(undefined) mockVersion.resetBehavior() mockVersion @@ -639,7 +639,7 @@ suite('Setup Test Suite', () => { mockExecuteCommand.restore() mockRunSetup.restore() stub(config, 'isPythonExtensionUsed').returns(true) - stub(setup, 'getEnvDetails').resolves(undefined) + stub(setup, 'getDvcCliDetails').resolves(undefined) mockVersion.resetBehavior() mockVersion.rejects(new Error('no CLI here')) diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index fddd88d261..412222ee58 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -70,7 +70,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: false, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: '1.0.0' }, hasData: false, @@ -100,7 +100,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: undefined }, hasData: false, @@ -124,7 +124,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: undefined }, hasData: false, @@ -152,7 +152,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - exampleCommand: `${defaultInterpreter} -m dvc`, + command: `${defaultInterpreter} -m dvc`, version: undefined }, hasData: false, @@ -179,7 +179,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: undefined }, hasData: false, @@ -206,7 +206,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: undefined }, hasData: false, @@ -233,7 +233,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: undefined, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: undefined }, hasData: false, @@ -260,7 +260,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -284,7 +284,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -306,7 +306,7 @@ describe('App', () => { canGitInitialize: true, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -331,7 +331,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -353,7 +353,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -375,7 +375,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -399,7 +399,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -426,7 +426,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -453,7 +453,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -480,7 +480,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -495,10 +495,10 @@ describe('App', () => { }) const envDetails = screen.getByTestId('dvc-env-details') - const exampleCommand = `1.0.0 (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + const command = `1.0.0 (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` expect(within(envDetails).getByText('Version')).toBeInTheDocument() - expect(within(envDetails).getByText(exampleCommand)).toBeInTheDocument() + expect(within(envDetails).getByText(command)).toBeInTheDocument() }) it('should tell the user that version is not found if dvc is not installed', () => { @@ -506,7 +506,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: false, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: undefined }, hasData: false, @@ -520,19 +520,19 @@ describe('App', () => { shareLiveToStudio: false }) const envDetails = screen.getByTestId('dvc-env-details') - const exampleCommand = `Not found (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + const command = `Not found (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` expect(within(envDetails).getByText('Version')).toBeInTheDocument() - expect(within(envDetails).getByText(exampleCommand)).toBeInTheDocument() + expect(within(envDetails).getByText(command)).toBeInTheDocument() }) it('should show the user an example command if dvc is installed', () => { - const exampleCommand = 'python -m dvc' + const command = 'python -m dvc' renderApp({ canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand, + command, version: '1.0.0' }, hasData: true, @@ -549,7 +549,7 @@ describe('App', () => { const envDetails = screen.getByTestId('dvc-env-details') expect(within(envDetails).getByText('Command')).toBeInTheDocument() - expect(within(envDetails).getByText(exampleCommand)).toBeInTheDocument() + expect(within(envDetails).getByText(command)).toBeInTheDocument() }) it('should show user an example command with a "Configure" button if dvc is installed without the python extension', () => { @@ -557,7 +557,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: '1.0.0' }, hasData: true, @@ -595,7 +595,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -637,7 +637,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -659,7 +659,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -688,7 +688,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: false, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: undefined }, hasData: false, @@ -710,7 +710,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -734,7 +734,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -756,7 +756,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: undefined, @@ -778,7 +778,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -802,7 +802,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: true, @@ -831,7 +831,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -855,7 +855,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -883,7 +883,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -911,7 +911,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -942,7 +942,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -970,7 +970,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, @@ -997,7 +997,7 @@ describe('App', () => { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'python -m dvc', + command: 'python -m dvc', version: '1.0.0' }, hasData: false, diff --git a/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx b/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx index d3291b1234..82c763087d 100644 --- a/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx +++ b/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx @@ -4,16 +4,16 @@ import styles from './styles.module.scss' import { selectPythonInterpreter, setupWorkspace } from '../messages' interface DvcEnvCommandRowProps { - exampleCommand: string + command: string isPythonExtensionInstalled: boolean } export const DvcEnvCommandRow: React.FC<DvcEnvCommandRowProps> = ({ - exampleCommand, + command, isPythonExtensionInstalled }) => { - const commandText = exampleCommand || 'Not found' - const command = ( + const commandText = command || 'Not found' + const commandValue = ( <> <span className={styles.command}>{commandText}</span> <span className={styles.actions}> @@ -35,5 +35,5 @@ export const DvcEnvCommandRow: React.FC<DvcEnvCommandRowProps> = ({ </> ) - return <DvcEnvInfoRow title="Command" text={command} /> + return <DvcEnvInfoRow title="Command" text={commandValue} /> } diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index ab6546aeeb..e63bf90181 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -10,7 +10,7 @@ interface DvcEnvDetailsProps extends DvcCliDetails { } export const DvcEnvDetails: React.FC<DvcEnvDetailsProps> = ({ - exampleCommand, + command, version, isPythonExtensionInstalled }) => { @@ -23,7 +23,7 @@ export const DvcEnvDetails: React.FC<DvcEnvDetailsProps> = ({ <tbody> {version && ( <DvcEnvCommandRow - exampleCommand={exampleCommand} + command={command} isPythonExtensionInstalled={isPythonExtensionInstalled} /> )} diff --git a/webview/src/stories/Setup.stories.tsx b/webview/src/stories/Setup.stories.tsx index 1076f81eae..8b87ed9afc 100644 --- a/webview/src/stories/Setup.stories.tsx +++ b/webview/src/stories/Setup.stories.tsx @@ -9,7 +9,7 @@ const DEFAULT_DATA: SetupData = { canGitInitialize: false, cliCompatible: true, dvcCliDetails: { - exampleCommand: 'path/to/python -m dvc', + command: 'path/to/python -m dvc', version: '1.0.0' }, hasData: false, @@ -77,7 +77,7 @@ export const NoCLIPythonNotFound = Template.bind({}) NoCLIPythonNotFound.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - exampleCommand: 'dvc', + command: 'dvc', version: undefined }, isPythonExtensionInstalled: false, @@ -88,7 +88,7 @@ export const NoCLIPythonExtensionUsed = Template.bind({}) NoCLIPythonExtensionUsed.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - exampleCommand: '/opt/homebrew/Caskroom/miniforge/base/bin/python -m dvc', + command: '/opt/homebrew/Caskroom/miniforge/base/bin/python -m dvc', version: undefined }, isPythonExtensionInstalled: true, @@ -99,7 +99,7 @@ export const NoCLIPythonExtensionNotUsed = Template.bind({}) NoCLIPythonExtensionNotUsed.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { - exampleCommand: '.env/bin/python -m dvc', + command: '.env/bin/python -m dvc', version: undefined }, isPythonExtensionInstalled: false, From d9662cc6a2cb3bc49ce354fbe7f54efd06a13474 Mon Sep 17 00:00:00 2001 From: julieg18 <juliannagal18@gmail.com> Date: Thu, 27 Apr 2023 13:18:48 -0500 Subject: [PATCH 20/20] Add back "Select Python Interpreter" --- extension/src/setup/index.ts | 13 ++- extension/src/setup/webview/contract.ts | 2 +- extension/src/setup/webview/messages.ts | 4 +- extension/src/test/suite/setup/index.test.ts | 8 +- webview/src/setup/components/App.test.tsx | 80 +++++++++---------- webview/src/setup/components/App.tsx | 8 +- webview/src/setup/components/dvc/Dvc.tsx | 6 +- .../setup/components/dvc/DvcEnvCommandRow.tsx | 6 +- .../setup/components/dvc/DvcEnvDetails.tsx | 8 +- webview/src/stories/Setup.stories.tsx | 26 +++--- 10 files changed, 81 insertions(+), 80 deletions(-) diff --git a/extension/src/setup/index.ts b/extension/src/setup/index.ts index e55a35d5ca..108d603d82 100644 --- a/extension/src/setup/index.ts +++ b/extension/src/setup/index.ts @@ -24,7 +24,6 @@ import { BaseWebview } from '../webview' import { ViewKey } from '../webview/constants' import { BaseRepository } from '../webview/repository' import { Resource } from '../resourceLocator' -import { isPythonExtensionInstalled } from '../extensions/python' import { findAbsoluteDvcRootPath, findDvcRootPaths, @@ -354,10 +353,19 @@ export class Setup } } + private isDVCBeingUsedGlobally() { + const dvcPath = this.config.getCliPath() + const pythonBinPath = this.config.getPythonBinPath() + + return dvcPath || !pythonBinPath + } + private async sendDataToWebview() { const projectInitialized = this.hasRoots() const hasData = this.getHasData() + const isPythonExtensionUsed = await this.isPythonExtensionUsed() + const needsGitInitialized = !projectInitialized && !!(await this.needsGitInit()) @@ -375,7 +383,8 @@ export class Setup cliCompatible: this.cliCompatible, dvcCliDetails, hasData, - isPythonExtensionInstalled: isPythonExtensionInstalled(), + isPythonExtensionUsed: + !this.isDVCBeingUsedGlobally() && isPythonExtensionUsed, isStudioConnected: this.studioIsConnected, needsGitCommit, needsGitInitialized, diff --git a/extension/src/setup/webview/contract.ts b/extension/src/setup/webview/contract.ts index 37f6368837..a0b8ad14e5 100644 --- a/extension/src/setup/webview/contract.ts +++ b/extension/src/setup/webview/contract.ts @@ -8,7 +8,7 @@ export type SetupData = { cliCompatible: boolean | undefined dvcCliDetails: DvcCliDetails hasData: boolean | undefined - isPythonExtensionInstalled: boolean + isPythonExtensionUsed: boolean isStudioConnected: boolean needsGitCommit: boolean needsGitInitialized: boolean | undefined diff --git a/extension/src/setup/webview/messages.ts b/extension/src/setup/webview/messages.ts index 7afdab1413..98527b4a12 100644 --- a/extension/src/setup/webview/messages.ts +++ b/extension/src/setup/webview/messages.ts @@ -37,7 +37,7 @@ export class WebviewMessages { cliCompatible, dvcCliDetails, hasData, - isPythonExtensionInstalled, + isPythonExtensionUsed, isStudioConnected, needsGitCommit, needsGitInitialized, @@ -51,7 +51,7 @@ export class WebviewMessages { cliCompatible, dvcCliDetails, hasData, - isPythonExtensionInstalled, + isPythonExtensionUsed, isStudioConnected, needsGitCommit, needsGitInitialized, diff --git a/extension/src/test/suite/setup/index.test.ts b/extension/src/test/suite/setup/index.test.ts index b4f40a76a0..5030e969cb 100644 --- a/extension/src/test/suite/setup/index.test.ts +++ b/extension/src/test/suite/setup/index.test.ts @@ -241,7 +241,7 @@ suite('Setup Test Suite', () => { cliCompatible: undefined, dvcCliDetails: { command: 'dvc', version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: true, needsGitInitialized: true, @@ -282,7 +282,7 @@ suite('Setup Test Suite', () => { cliCompatible: true, dvcCliDetails: { command: 'dvc', version: MIN_CLI_VERSION }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: true, needsGitInitialized: true, @@ -332,7 +332,7 @@ suite('Setup Test Suite', () => { version: MIN_CLI_VERSION }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: false, @@ -382,7 +382,7 @@ suite('Setup Test Suite', () => { version: MIN_CLI_VERSION }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: true, needsGitInitialized: false, diff --git a/webview/src/setup/components/App.test.tsx b/webview/src/setup/components/App.test.tsx index 412222ee58..57a83d71d6 100644 --- a/webview/src/setup/components/App.test.tsx +++ b/webview/src/setup/components/App.test.tsx @@ -21,7 +21,7 @@ const renderApp = ({ cliCompatible, dvcCliDetails, hasData, - isPythonExtensionInstalled, + isPythonExtensionUsed, isStudioConnected, needsGitInitialized, needsGitCommit, @@ -40,7 +40,7 @@ const renderApp = ({ cliCompatible, dvcCliDetails, hasData, - isPythonExtensionInstalled, + isPythonExtensionUsed, isStudioConnected, needsGitCommit, needsGitInitialized, @@ -74,7 +74,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -104,7 +104,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -128,7 +128,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -156,7 +156,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -183,7 +183,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -210,7 +210,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -237,7 +237,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -264,7 +264,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -288,7 +288,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: true, @@ -310,7 +310,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: true, @@ -335,7 +335,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: true, @@ -357,7 +357,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -379,7 +379,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -403,7 +403,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -430,7 +430,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -457,7 +457,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -484,7 +484,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -495,7 +495,7 @@ describe('App', () => { }) const envDetails = screen.getByTestId('dvc-env-details') - const command = `1.0.0 (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + const command = `1.0.0 (${MIN_CLI_VERSION} <= required < ${MAX_CLI_VERSION}.0.0)` expect(within(envDetails).getByText('Version')).toBeInTheDocument() expect(within(envDetails).getByText(command)).toBeInTheDocument() @@ -510,7 +510,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -520,7 +520,7 @@ describe('App', () => { shareLiveToStudio: false }) const envDetails = screen.getByTestId('dvc-env-details') - const command = `Not found (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + const command = `Not found (${MIN_CLI_VERSION} <= required < ${MAX_CLI_VERSION}.0.0)` expect(within(envDetails).getByText('Version')).toBeInTheDocument() expect(within(envDetails).getByText(command)).toBeInTheDocument() @@ -536,7 +536,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -561,7 +561,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -599,7 +599,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -641,7 +641,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: true, needsGitInitialized: true, @@ -663,7 +663,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: true, needsGitInitialized: true, @@ -692,7 +692,7 @@ describe('App', () => { version: undefined }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -714,7 +714,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -738,7 +738,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: true, needsGitInitialized: false, @@ -760,7 +760,7 @@ describe('App', () => { version: '1.0.0' }, hasData: undefined, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -782,7 +782,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: undefined, @@ -806,7 +806,7 @@ describe('App', () => { version: '1.0.0' }, hasData: true, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -835,7 +835,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: false, @@ -859,7 +859,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: false, @@ -887,7 +887,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: false, @@ -915,7 +915,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: false, needsGitCommit: false, needsGitInitialized: false, @@ -946,7 +946,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -974,7 +974,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -1001,7 +1001,7 @@ describe('App', () => { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, diff --git a/webview/src/setup/components/App.tsx b/webview/src/setup/components/App.tsx index b65c7857e0..540bddfe8c 100644 --- a/webview/src/setup/components/App.tsx +++ b/webview/src/setup/components/App.tsx @@ -34,7 +34,7 @@ export const App: React.FC = () => { const [pythonBinPath, setPythonBinPath] = useState<string | undefined>( undefined ) - const [isPythonExtensionInstalled, setIsPythonExtensionInstalled] = + const [isPythonExtensionUsed, setisPythonExtensionUsed] = useState<boolean>(false) const [hasData, setHasData] = useState<boolean | undefined>(false) const [sectionCollapsed, setSectionCollapsed] = useState( @@ -51,7 +51,7 @@ export const App: React.FC = () => { setCliCompatible(data.data.cliCompatible) setHasData(data.data.hasData) setDvcCliDetails(data.data.dvcCliDetails) - setIsPythonExtensionInstalled(data.data.isPythonExtensionInstalled) + setisPythonExtensionUsed(data.data.isPythonExtensionUsed) setNeedsGitInitialized(data.data.needsGitInitialized) setNeedsGitCommit(data.data.needsGitCommit) setProjectInitialized(data.data.projectInitialized) @@ -67,7 +67,7 @@ export const App: React.FC = () => { setCliCompatible, setHasData, setDvcCliDetails, - setIsPythonExtensionInstalled, + setisPythonExtensionUsed, setNeedsGitInitialized, setNeedsGitCommit, setProjectInitialized, @@ -99,7 +99,7 @@ export const App: React.FC = () => { canGitInitialize={canGitInitialize} cliCompatible={cliCompatible} dvcCliDetails={dvcCliDetails} - isPythonExtensionInstalled={isPythonExtensionInstalled} + isPythonExtensionUsed={isPythonExtensionUsed} needsGitInitialized={needsGitInitialized} projectInitialized={projectInitialized} pythonBinPath={pythonBinPath} diff --git a/webview/src/setup/components/dvc/Dvc.tsx b/webview/src/setup/components/dvc/Dvc.tsx index 410b7a526c..fd98a52f83 100644 --- a/webview/src/setup/components/dvc/Dvc.tsx +++ b/webview/src/setup/components/dvc/Dvc.tsx @@ -20,7 +20,7 @@ export type DvcProps = { canGitInitialize: boolean | undefined cliCompatible: boolean | undefined dvcCliDetails: DvcCliDetails | undefined - isPythonExtensionInstalled: boolean + isPythonExtensionUsed: boolean needsGitInitialized: boolean | undefined projectInitialized: boolean pythonBinPath: string | undefined @@ -32,7 +32,7 @@ export const Dvc: React.FC<DvcProps> = ({ canGitInitialize, cliCompatible, dvcCliDetails, - isPythonExtensionInstalled, + isPythonExtensionUsed, needsGitInitialized, projectInitialized, pythonBinPath, @@ -42,7 +42,7 @@ export const Dvc: React.FC<DvcProps> = ({ const children = dvcCliDetails && ( <DvcEnvDetails {...dvcCliDetails} - isPythonExtensionInstalled={isPythonExtensionInstalled} + isPythonExtensionUsed={isPythonExtensionUsed} /> ) diff --git a/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx b/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx index 82c763087d..422bab99e5 100644 --- a/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx +++ b/webview/src/setup/components/dvc/DvcEnvCommandRow.tsx @@ -5,12 +5,12 @@ import { selectPythonInterpreter, setupWorkspace } from '../messages' interface DvcEnvCommandRowProps { command: string - isPythonExtensionInstalled: boolean + isPythonExtensionUsed: boolean } export const DvcEnvCommandRow: React.FC<DvcEnvCommandRowProps> = ({ command, - isPythonExtensionInstalled + isPythonExtensionUsed }) => { const commandText = command || 'Not found' const commandValue = ( @@ -20,7 +20,7 @@ export const DvcEnvCommandRow: React.FC<DvcEnvCommandRowProps> = ({ <button className={styles.buttonAsLink} onClick={setupWorkspace}> Configure </button> - {isPythonExtensionInstalled && ( + {isPythonExtensionUsed && ( <> <span className={styles.separator} /> <button diff --git a/webview/src/setup/components/dvc/DvcEnvDetails.tsx b/webview/src/setup/components/dvc/DvcEnvDetails.tsx index e63bf90181..5622749f8b 100644 --- a/webview/src/setup/components/dvc/DvcEnvDetails.tsx +++ b/webview/src/setup/components/dvc/DvcEnvDetails.tsx @@ -6,25 +6,25 @@ import styles from './styles.module.scss' import { DvcEnvCommandRow } from './DvcEnvCommandRow' interface DvcEnvDetailsProps extends DvcCliDetails { - isPythonExtensionInstalled: boolean + isPythonExtensionUsed: boolean } export const DvcEnvDetails: React.FC<DvcEnvDetailsProps> = ({ command, version, - isPythonExtensionInstalled + isPythonExtensionUsed }) => { const versionText = `${ version || 'Not found' - } (required >= ${MIN_CLI_VERSION} and < ${MAX_CLI_VERSION}.0.0)` + } (${MIN_CLI_VERSION} <= required < ${MAX_CLI_VERSION}.0.0)` return ( <table data-testid="dvc-env-details" className={styles.envDetails}> <tbody> {version && ( <DvcEnvCommandRow + isPythonExtensionUsed={isPythonExtensionUsed} command={command} - isPythonExtensionInstalled={isPythonExtensionInstalled} /> )} <DvcEnvInfoRow title="Version" text={versionText} /> diff --git a/webview/src/stories/Setup.stories.tsx b/webview/src/stories/Setup.stories.tsx index 8b87ed9afc..24a99bb6c0 100644 --- a/webview/src/stories/Setup.stories.tsx +++ b/webview/src/stories/Setup.stories.tsx @@ -13,7 +13,7 @@ const DEFAULT_DATA: SetupData = { version: '1.0.0' }, hasData: false, - isPythonExtensionInstalled: true, + isPythonExtensionUsed: true, isStudioConnected: true, needsGitCommit: false, needsGitInitialized: false, @@ -65,7 +65,6 @@ NoDataNotConnected.args = getUpdatedArgs({ }) export const CompletedConnected = Template.bind({}) - CompletedConnected.args = getUpdatedArgs({ hasData: true, isStudioConnected: true, @@ -80,32 +79,20 @@ NoCLIPythonNotFound.args = getUpdatedArgs({ command: 'dvc', version: undefined }, - isPythonExtensionInstalled: false, + isPythonExtensionUsed: false, pythonBinPath: undefined }) -export const NoCLIPythonExtensionUsed = Template.bind({}) -NoCLIPythonExtensionUsed.args = getUpdatedArgs({ +export const NoCLIPythonFound = Template.bind({}) +NoCLIPythonFound.args = getUpdatedArgs({ cliCompatible: undefined, dvcCliDetails: { command: '/opt/homebrew/Caskroom/miniforge/base/bin/python -m dvc', version: undefined }, - isPythonExtensionInstalled: true, pythonBinPath: '/opt/homebrew/Caskroom/miniforge/base/bin/python' }) -export const NoCLIPythonExtensionNotUsed = Template.bind({}) -NoCLIPythonExtensionNotUsed.args = getUpdatedArgs({ - cliCompatible: undefined, - dvcCliDetails: { - command: '.env/bin/python -m dvc', - version: undefined - }, - isPythonExtensionInstalled: false, - pythonBinPath: '.env/bin/python' -}) - export const CliFoundButNotCompatible = Template.bind({}) CliFoundButNotCompatible.args = getUpdatedArgs({ cliCompatible: false @@ -131,3 +118,8 @@ DvcUninitialized.args = getUpdatedArgs({ needsGitInitialized: undefined, projectInitialized: false }) + +export const CliFoundManually = Template.bind({}) +CliFoundManually.args = getUpdatedArgs({ + isPythonExtensionUsed: false +})