From 5c14e0de5b63eaa5be6f5063d5cb914babe6953b Mon Sep 17 00:00:00 2001 From: sharon wang Date: Fri, 5 Apr 2024 12:53:24 -0400 Subject: [PATCH 1/9] update the project config state based on dropdown selections - store the python environment setup type in the project config - move all project wizard related enums to newProjectWizardEnums.ts - store the envSetupType, envType and selectedInterpreter in the pythonEnvironmentStep state and update accordingly - define the PythonEnvironmentType enum in newProjectWizardEnums.ts - set the interpreter drop down to disabled while the interpreters are still being loaded - ensure the env setup type, env type and selected interpreter configs are persisted and restored when navigating back and forth between steps --- .../steps/projectNameLocationStep.tsx | 5 +- .../components/steps/projectTypeStep.tsx | 3 +- .../steps/pythonEnvironmentStep.tsx | 118 ++++++++++-------- .../interfaces/newProjectWizardEnums.ts | 24 ++++ .../newProjectWizardState.tsx | 32 ++--- ...Utils.ts => pythonEnvironmentStepUtils.ts} | 66 ++++++++-- 6 files changed, 156 insertions(+), 92 deletions(-) rename src/vs/workbench/browser/positronNewProjectWizard/utilities/{pythonInterpreterListUtils.ts => pythonEnvironmentStepUtils.ts} (60%) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectNameLocationStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectNameLocationStep.tsx index 8d73717e414..472fefa5102 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectNameLocationStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectNameLocationStep.tsx @@ -7,9 +7,8 @@ import { PropsWithChildren } from 'react'; // eslint-disable-line no-duplicate- import { localize } from 'vs/nls'; import { useNewProjectWizardContext } from 'vs/workbench/browser/positronNewProjectWizard/newProjectWizardContext'; import { URI } from 'vs/base/common/uri'; -import { NewProjectWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; +import { NewProjectType, NewProjectWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { NewProjectWizardStepProps } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardStepProps'; -import { NewProjectType } from 'vs/workbench/browser/positronNewProjectWizard/newProjectWizardState'; import { PositronWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/components/wizardStep'; import { PositronWizardSubStep } from 'vs/workbench/browser/positronNewProjectWizard/components/wizardSubStep'; import { LabeledTextInput } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/labeledTextInput'; @@ -106,7 +105,7 @@ export const ProjectNameLocationStep = (props: PropsWithChildrenformatted + value={projectConfig.parentFolder} // TODO: this should be formatted onBrowse={browseHandler} onChange={e => setProjectConfig({ ...projectConfig, parentFolder: e.target.value })} /> diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx index 669018944d4..056456cbfc6 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/projectTypeStep.tsx @@ -8,9 +8,8 @@ import { PropsWithChildren } from 'react'; // eslint-disable-line no-duplicate- import { Button } from 'vs/base/browser/ui/positronComponents/button/button'; import { localize } from 'vs/nls'; import { useNewProjectWizardContext } from 'vs/workbench/browser/positronNewProjectWizard/newProjectWizardContext'; -import { NewProjectWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; +import { NewProjectType, NewProjectWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { NewProjectWizardStepProps } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardStepProps'; -import { NewProjectType } from 'vs/workbench/browser/positronNewProjectWizard/newProjectWizardState'; import { OKCancelBackNextActionBar } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/okCancelBackNextActionBar'; /** diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx index c0f1646a185..51a1f944665 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx @@ -12,14 +12,14 @@ import { NewProjectWizardStepProps } from 'vs/workbench/browser/positronNewProje import { localize } from 'vs/nls'; import { RuntimeStartupPhase } from 'vs/workbench/services/runtimeStartup/common/runtimeStartupService'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { createCondaInterpreterDropDownItems, createPythonInterpreterDropDownItems, createVenvInterpreterDropDownItems } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonInterpreterListUtils'; +import { getPythonInterpreterEntries, getSelectedPythonInterpreterId, locationForNewEnv } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils'; import { PositronWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/components/wizardStep'; import { PositronWizardSubStep } from 'vs/workbench/browser/positronNewProjectWizard/components/wizardSubStep'; import { DropDownListBoxItem } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBoxItem'; import { DropDownListBox } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBox'; import { RadioButtonItem } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/radioButton'; import { RadioGroup } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/radioGroup'; -import { EnvironmentSetupType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; +import { EnvironmentSetupType, PythonEnvironmentType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { PythonInterpreterEntry } from 'vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry'; /** @@ -39,27 +39,33 @@ export const PythonEnvironmentStep = (props: PropsWithChildren( + getSelectedPythonInterpreterId( + projectConfig.selectedRuntime?.runtimeId, + newProjectWizardState.runtimeStartupService + ) + ); const [interpreterEntries, setInterpreterEntries] = useState( // It's possible that the runtime discovery phase is not complete, so we need to check // for that before creating the interpreter entries. startupPhase !== RuntimeStartupPhase.Complete ? [] : - // TODO: we currently populate the interpreter entries with all registered runtimes, - // but we'll want to call the Venv or Conda interpreter creation functions based on - // the default selection. - createPythonInterpreterDropDownItems( + getPythonInterpreterEntries( newProjectWizardState.runtimeStartupService, - newProjectWizardState.languageRuntimeService + newProjectWizardState.languageRuntimeService, + envSetupType, + envType ) ); - const [envSetupType, setEnvSetupType] = useState(EnvironmentSetupType.NewEnvironment); // TODO: retrieve the python environment types from the language runtime service somehow? // TODO: localize these entries const envTypeEntries = [ - new DropDownListBoxItem({ identifier: 'Venv', title: 'Venv' + ' Creates a `.venv` virtual environment for your project', value: 'Venv' }), - new DropDownListBoxItem({ identifier: 'Conda', title: 'Conda' + ' Creates a `.conda` Conda environment for your project', value: 'Conda' }) + new DropDownListBoxItem({ identifier: PythonEnvironmentType.Venv, title: PythonEnvironmentType.Venv + ' Creates a `.venv` virtual environment for your project', value: PythonEnvironmentType.Venv }), + new DropDownListBoxItem({ identifier: PythonEnvironmentType.Conda, title: PythonEnvironmentType.Conda + ' Creates a `.conda` Conda environment for your project', value: PythonEnvironmentType.Conda }) ]; const envSetupRadioButtons: RadioButtonItem[] = [ @@ -70,46 +76,52 @@ export const PythonEnvironmentStep = (props: PropsWithChildren { - // Verify that the identifier is a valid EnvironmentSetupType value - if (Object.values(EnvironmentSetupType).includes(identifier as EnvironmentSetupType)) { - setEnvSetupType(identifier as EnvironmentSetupType); - // If the user selects an existing environment, update the interpreter entries dropdown - // to show the unfiltered list of all existing interpreters. - if (identifier === EnvironmentSetupType.ExistingEnvironment) { - setInterpreterEntries( - createPythonInterpreterDropDownItems( - newProjectWizardState.runtimeStartupService, - newProjectWizardState.languageRuntimeService - ) - ); - } - } else { - // This shouldn't happen, since the RadioGroup should only allow selection of the - // EnvironmentSetupType values - logService.error(`Unknown environment setup type: ${identifier}`); - } + const onEnvSetupSelected = (pythonEnvSetupType: EnvironmentSetupType) => { + setEnvSetupType(pythonEnvSetupType); + // If the user selects an existing environment, update the interpreter entries dropdown + // to show the unfiltered list of all existing interpreters. + setInterpreterEntries( + getPythonInterpreterEntries( + newProjectWizardState.runtimeStartupService, + newProjectWizardState.languageRuntimeService, + pythonEnvSetupType, + envType + ) + ); + setSelectedInterpreter( + getSelectedPythonInterpreterId( + projectConfig.selectedRuntime?.runtimeId, + newProjectWizardState.runtimeStartupService + ) + ); + setProjectConfig({ ...projectConfig, pythonEnvSetupType }); }; // Handler for when the environment type is selected. The interpreter entries are updated based // on the selected environment type, and the project configuration is updated as well. - const onEnvTypeSelected = (identifier: string) => { - switch (identifier) { - case 'Venv': - setInterpreterEntries(createVenvInterpreterDropDownItems(newProjectWizardState.runtimeStartupService, newProjectWizardState.languageRuntimeService)); - break; - case 'Conda': - setInterpreterEntries(createCondaInterpreterDropDownItems()); - break; - default: - logService.error(`Unknown environment type: ${identifier}`); - } - setProjectConfig({ ...projectConfig, pythonEnvType: identifier }); + const onEnvTypeSelected = (pythonEnvType: PythonEnvironmentType) => { + setEnvType(pythonEnvType); + setInterpreterEntries( + getPythonInterpreterEntries( + newProjectWizardState.runtimeStartupService, + newProjectWizardState.languageRuntimeService, + envSetupType, + pythonEnvType + ) + ); + setSelectedInterpreter( + getSelectedPythonInterpreterId( + projectConfig.selectedRuntime?.runtimeId, + newProjectWizardState.runtimeStartupService + ) + ); + setProjectConfig({ ...projectConfig, pythonEnvType }); }; // Handler for when the interpreter is selected. The project configuration is updated with the // selected interpreter. const onInterpreterSelected = (identifier: string) => { + setSelectedInterpreter(identifier); const selectedRuntime = newProjectWizardState.languageRuntimeService.getRegisteredRuntime(identifier); if (!selectedRuntime) { // This shouldn't happen, since the DropDownListBox should only allow selection of registered @@ -133,14 +145,13 @@ export const PythonEnvironmentStep = (props: PropsWithChildren { if (phase === RuntimeStartupPhase.Complete) { - // TODO: instead of calling createPythonInterpreterComboBoxItems, it should - // be aware of the defaults set by the environment type (Venv, Conda) - setInterpreterEntries( - createPythonInterpreterDropDownItems( - newProjectWizardState.runtimeStartupService, - newProjectWizardState.languageRuntimeService - ) + const entries = getPythonInterpreterEntries( + newProjectWizardState.runtimeStartupService, + newProjectWizardState.languageRuntimeService, + envSetupType, + envType ); + setInterpreterEntries(entries); } setStartupPhase(phase); } @@ -178,8 +189,8 @@ export const PythonEnvironmentStep = (props: PropsWithChildren onEnvSetupSelected(identifier)} + initialSelectionId={projectConfig.pythonEnvSetupType} + onSelectionChanged={identifier => onEnvSetupSelected(identifier as EnvironmentSetupType)} /> {envSetupType === EnvironmentSetupType.NewEnvironment ? @@ -192,15 +203,13 @@ export const PythonEnvironmentStep = (props: PropsWithChildren localize( 'pythonEnvironmentSubStep.feedback', 'The {0} environment will be created at: {1}', - projectConfig.pythonEnvType, - `${projectConfig.parentFolder}/${projectConfig.projectName}/${projectConfig.pythonEnvType === 'Venv' ? '.venv' : 'Conda' ? '.conda' : ''}` + envType, + locationForNewEnv(projectConfig.parentFolder, projectConfig.projectName, envType) ))()} > - {/* TODO: how to pre-select an option? */} } diff --git a/src/vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums.ts b/src/vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums.ts index 8572c31e12e..81d79f77eae 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums.ts +++ b/src/vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums.ts @@ -24,3 +24,27 @@ export enum EnvironmentSetupType { NewEnvironment = 'newEnvironment', ExistingEnvironment = 'existingEnvironment' } + +/** + * PythonEnvironmentType enum includes the types of Python environments. + * - Venv: A virtual environment. + * - Conda: A conda environment. + * TODO: retrieve these values from the appropriate extensions/services? + */ +export enum PythonEnvironmentType { + Venv = 'Venv', + Conda = 'Conda' +} + +/** + * NewProjectType enum. Defines the types of projects that can be created. + * TODO: localize. Since this is an enum, we can't use the localize function + * because computed values must be numbers (not strings). So we'll probably need to + * turn this into an object with keys and values, maybe also using something like + * satisfies Readonly>. + */ +export enum NewProjectType { + PythonProject = 'Python Project', + RProject = 'R Project', + JupyterNotebook = 'Jupyter Notebook' +} diff --git a/src/vs/workbench/browser/positronNewProjectWizard/newProjectWizardState.tsx b/src/vs/workbench/browser/positronNewProjectWizard/newProjectWizardState.tsx index 4f75a262e3d..3dbfdf510d6 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/newProjectWizardState.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/newProjectWizardState.tsx @@ -7,7 +7,7 @@ import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; import { ILanguageRuntimeMetadata, ILanguageRuntimeService } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService'; import { IRuntimeSessionService } from 'vs/workbench/services/runtimeSession/common/runtimeSessionService'; import { IRuntimeStartupService } from 'vs/workbench/services/runtimeStartup/common/runtimeStartupService'; -import { NewProjectWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; +import { EnvironmentSetupType, NewProjectType, NewProjectWizardStep, PythonEnvironmentType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { ILogService } from 'vs/platform/log/common/log'; @@ -16,7 +16,7 @@ import { ILogService } from 'vs/platform/log/common/log'; * NewProjectWizardServices interface. Defines the set of services that are required by the New * Project Wizard. */ -export interface NewProjectWizardServices { +interface NewProjectWizardServices { fileDialogService: IFileDialogService; keybindingService: IKeybindingService; languageRuntimeService: ILanguageRuntimeService; @@ -35,32 +35,19 @@ export interface NewProjectWizardStateProps { readonly parentFolder: string; } -/** - * NewProjectType enum. Defines the types of projects that can be created. - * TODO: this should be moved to a more appropriate location. - * TODO: localize. Since this is an enum, we can't use the localize function - * because computed values must be numbers (not strings). So we'll probably need to - * turn this into an object with keys and values, maybe also using something like - * satisfies Readonly>. - */ -export enum NewProjectType { - PythonProject = 'Python Project', - RProject = 'R Project', - JupyterNotebook = 'Jupyter Notebook' -} - /** * NewProjectConfiguration interface. Defines the configuration for a new project. * This information is used to initialize the workspace for a new project. */ export interface NewProjectConfiguration { - readonly selectedRuntime: ILanguageRuntimeMetadata; - readonly projectType: NewProjectType | ''; + readonly selectedRuntime: ILanguageRuntimeMetadata | undefined; + readonly projectType: NewProjectType | undefined; readonly projectName: string; readonly parentFolder: string; readonly initGitRepo: boolean; readonly openInNewWindow: boolean; - readonly pythonEnvType?: string; + readonly pythonEnvSetupType: EnvironmentSetupType; + readonly pythonEnvType: PythonEnvironmentType; } /** @@ -85,13 +72,14 @@ export const useNewProjectWizardState = ( ): NewProjectWizardState => { // Hooks. const [projectConfig, setProjectConfig] = useState({ - selectedRuntime: props.services.languageRuntimeService.registeredRuntimes[0], - projectType: '', + selectedRuntime: undefined, + projectType: undefined, projectName: '', parentFolder: props.parentFolder ?? '', initGitRepo: false, openInNewWindow: true, - pythonEnvType: '' + pythonEnvSetupType: EnvironmentSetupType.NewEnvironment, + pythonEnvType: PythonEnvironmentType.Venv, }); // TODO: the initial step should be passed in via the props diff --git a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonInterpreterListUtils.ts b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts similarity index 60% rename from src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonInterpreterListUtils.ts rename to src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts index 6bf0f6f1c47..560b4049700 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonInterpreterListUtils.ts +++ b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts @@ -5,6 +5,7 @@ import { DropDownListBoxEntry } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBox'; import { DropDownListBoxItem } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBoxItem'; import { DropDownListBoxSeparator } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBoxSeparator'; +import { EnvironmentSetupType, PythonEnvironmentType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { ILanguageRuntimeService } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService'; import { IRuntimeStartupService } from 'vs/workbench/services/runtimeStartup/common/runtimeStartupService'; @@ -75,6 +76,23 @@ const getPythonInterpreterDropDownItems = ( }, []); }; +/** + * Retrieves the runtimeId of the preferred interpreter for the given languageId. + * @param runtimeStartupService The runtime startup service. + * @param languageId The languageId of the runtime to retrieve. + * @returns The runtimeId of the preferred interpreter or undefined if no preferred runtime is found. + */ +export const getPreferredRuntimeId = (runtimeStartupService: IRuntimeStartupService, languageId: string) => { + let preferredRuntime; + try { + preferredRuntime = runtimeStartupService.getPreferredRuntime(languageId); + } catch (error) { + // Ignore the error if the preferred runtime is not found. This can happen if the interpreters + // are still being loaded. + } + return preferredRuntime?.runtimeId; +}; + /** * Creates an array of DropDownListBoxItem of Python interpreters for each Conda-supported minor * Python version. @@ -95,22 +113,48 @@ export const createCondaInterpreterDropDownItems = () => { }; /** - * Creates an array of DropDownListBoxItem for Global Python interpreters. + * Gets the Python interpreter entries based on the environment setup type and environment type. * @param runtimeStartupService The runtime startup service. * @param languageRuntimeService The language runtime service. - * @returns An array of DropDownListBoxItem for Venv Python interpreters. + * @param envSetupType The environment setup type. + * @param envType The environment type. + * @returns An array of DropDownListBoxItem and DropDownListBoxSeparator for Python interpreters. */ -export const createVenvInterpreterDropDownItems = (runtimeStartupService: IRuntimeStartupService, languageRuntimeService: ILanguageRuntimeService) => { - return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.Global); +export const getPythonInterpreterEntries = (runtimeStartupService: IRuntimeStartupService, languageRuntimeService: ILanguageRuntimeService, envSetupType: EnvironmentSetupType, envType: PythonEnvironmentType) => { + switch (envSetupType) { + case EnvironmentSetupType.NewEnvironment: + switch (envType) { + case PythonEnvironmentType.Venv: + return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.Global); + case PythonEnvironmentType.Conda: + return createCondaInterpreterDropDownItems(); + default: + return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.All); + } + case EnvironmentSetupType.ExistingEnvironment: + return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.All); + default: + return []; + } }; /** - * Creates an array of DropDownListBoxItem and DropDownListBoxSeparator for all detected Python - * interpreters, grouped by the runtime sources (Global, Venv, Conda, etc.). - * @param runtimeStartupService The runtime startup service. - * @param languageRuntimeService The language runtime service. - * @returns An array of DropDownListBoxItem and DropDownListBoxSeparator. + * Constructs the location for the new Python environment based on the parent folder, project name, + * and environment type. + * @param parentFolder The parent folder for the new environment. + * @param projectName The name of the project. + * @param envType The type of Python environment. + * @returns The location for the new Python environment. */ -export const createPythonInterpreterDropDownItems = (runtimeStartupService: IRuntimeStartupService, languageRuntimeService: ILanguageRuntimeService) => { - return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.All); +export const locationForNewEnv = (parentFolder: string, projectName: string, envType: PythonEnvironmentType) => { + const envDir = envType === PythonEnvironmentType.Venv ? '.venv' : envType === PythonEnvironmentType.Conda ? '.conda' : ''; + return `${parentFolder}/${projectName}/${envDir}`; +}; + +export const getSelectedPythonInterpreterId = (existingSelection: string | undefined, runtimeStartupService: IRuntimeStartupService) => { + if (existingSelection) { + return existingSelection; + } + const preferredRuntimeId = getPreferredRuntimeId(runtimeStartupService, 'python'); + return preferredRuntimeId ?? ''; }; From c7e259c5a6da7d7f295a0645aeb88f0387485130 Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 15:40:46 -0400 Subject: [PATCH 2/9] address merge conflict issues --- .../components/steps/pythonEnvironmentStep.tsx | 1 + .../components/steps/pythonInterpreterEntry.tsx | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx index 51a1f944665..41b0b1eae85 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx @@ -217,6 +217,7 @@ export const PythonEnvironmentStep = (props: PropsWithChildren onEnvTypeSelected(dropDownListBoxItem.options.identifier)} /> diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx index 125f3792087..8dd0cf2d12e 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx @@ -9,7 +9,7 @@ import 'vs/css!./pythonInterpreterEntry'; import * as React from 'react'; // Other dependencies. -import { PythonInterpreterInfo } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonInterpreterListUtils'; +import { PythonInterpreterInfo } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils'; /** * PythonInterpreterEntryProps interface. From cd1a8fd9a6769c0ff016df864474c87672f88230 Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 16:05:06 -0400 Subject: [PATCH 3/9] update dropdown items for Conda interpreter --- .../utilities/pythonEnvironmentStepUtils.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts index 560b4049700..017c14f7196 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts +++ b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts @@ -101,12 +101,18 @@ export const getPreferredRuntimeId = (runtimeStartupService: IRuntimeStartupServ export const createCondaInterpreterDropDownItems = () => { // TODO: we should get the list of Python versions from the Conda service const pythonVersions = ['3.12', '3.11', '3.10', '3.9', '3.8']; - const condaRuntimes: DropDownListBoxItem[] = []; + const condaRuntimes: DropDownListBoxItem[] = []; pythonVersions.forEach(version => { - condaRuntimes.push(new DropDownListBoxItem({ + condaRuntimes.push(new DropDownListBoxItem({ identifier: `conda-python-${version}`, - title: `Python ${version}`, - value: `conda-python-${version}` + value: { + preferred: version === '3.12', + runtimeId: `conda-python-${version}`, + languageName: 'Python', + languageVersion: version, + runtimePath: '', + runtimeSource: 'Conda' + } })); }); return condaRuntimes; From 46374da82a3dcf7691cc0fb7bfc6e3c23a680922 Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 16:08:36 -0400 Subject: [PATCH 4/9] set selected interpreter once runtimeStartup is complete --- .../components/steps/pythonEnvironmentStep.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx index 41b0b1eae85..1da6b54034c 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx @@ -152,6 +152,12 @@ export const PythonEnvironmentStep = (props: PropsWithChildren Date: Wed, 10 Apr 2024 16:13:29 -0400 Subject: [PATCH 5/9] add jsdoc for python env step utils --- .../utilities/pythonEnvironmentStepUtils.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts index 017c14f7196..04da3fa5734 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts +++ b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts @@ -9,6 +9,9 @@ import { EnvironmentSetupType, PythonEnvironmentType } from 'vs/workbench/browse import { ILanguageRuntimeService } from 'vs/workbench/services/languageRuntime/common/languageRuntimeService'; import { IRuntimeStartupService } from 'vs/workbench/services/runtimeStartup/common/runtimeStartupService'; +/** + * PythonRuntimeFilter enum. + */ export enum PythonRuntimeFilter { All = 'All', // Include all runtimes. This is when an existing Python installation is to be used. Global = 'Global', // Include only global runtimes. This is when a new Venv environment is being created. @@ -157,6 +160,14 @@ export const locationForNewEnv = (parentFolder: string, projectName: string, env return `${parentFolder}/${projectName}/${envDir}`; }; +/** + * Returns the runtime ID of the Python interpreter that should be selected in the dropdown box. + * If an existing selection is provided, it is returned. Otherwise, the preferred runtime ID is + * returned if available. + * @param existingSelection The existing selected interpreter ID. + * @param runtimeStartupService The runtime startup service. + * @returns The runtime ID of the selected Python interpreter. + */ export const getSelectedPythonInterpreterId = (existingSelection: string | undefined, runtimeStartupService: IRuntimeStartupService) => { if (existingSelection) { return existingSelection; From ac6673e489b5f31eeb378c4acd1e387dcc7b957c Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 16:29:18 -0400 Subject: [PATCH 6/9] format pythonEnvironmentStepUtils.ts --- .../utilities/pythonEnvironmentStepUtils.ts | 50 ++++++++++++++----- 1 file changed, 38 insertions(+), 12 deletions(-) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts index 04da3fa5734..4bfbba98846 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts +++ b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts @@ -129,19 +129,36 @@ export const createCondaInterpreterDropDownItems = () => { * @param envType The environment type. * @returns An array of DropDownListBoxItem and DropDownListBoxSeparator for Python interpreters. */ -export const getPythonInterpreterEntries = (runtimeStartupService: IRuntimeStartupService, languageRuntimeService: ILanguageRuntimeService, envSetupType: EnvironmentSetupType, envType: PythonEnvironmentType) => { +export const getPythonInterpreterEntries = ( + runtimeStartupService: IRuntimeStartupService, + languageRuntimeService: ILanguageRuntimeService, + envSetupType: EnvironmentSetupType, + envType: PythonEnvironmentType +) => { switch (envSetupType) { case EnvironmentSetupType.NewEnvironment: switch (envType) { case PythonEnvironmentType.Venv: - return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.Global); + return getPythonInterpreterDropDownItems( + runtimeStartupService, + languageRuntimeService, + PythonRuntimeFilter.Global + ); case PythonEnvironmentType.Conda: return createCondaInterpreterDropDownItems(); default: - return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.All); + return getPythonInterpreterDropDownItems( + runtimeStartupService, + languageRuntimeService, + PythonRuntimeFilter.All + ); } case EnvironmentSetupType.ExistingEnvironment: - return getPythonInterpreterDropDownItems(runtimeStartupService, languageRuntimeService, PythonRuntimeFilter.All); + return getPythonInterpreterDropDownItems( + runtimeStartupService, + languageRuntimeService, + PythonRuntimeFilter.All + ); default: return []; } @@ -155,8 +172,18 @@ export const getPythonInterpreterEntries = (runtimeStartupService: IRuntimeStart * @param envType The type of Python environment. * @returns The location for the new Python environment. */ -export const locationForNewEnv = (parentFolder: string, projectName: string, envType: PythonEnvironmentType) => { - const envDir = envType === PythonEnvironmentType.Venv ? '.venv' : envType === PythonEnvironmentType.Conda ? '.conda' : ''; +export const locationForNewEnv = ( + parentFolder: string, + projectName: string, + envType: PythonEnvironmentType +) => { + // TODO: this only works for Venv and Conda environments. We'll need to expand on this to add + // support for other environment types. + const envDir = envType === PythonEnvironmentType.Venv + ? '.venv' + : envType === PythonEnvironmentType.Conda + ? '.conda' + : ''; return `${parentFolder}/${projectName}/${envDir}`; }; @@ -168,10 +195,9 @@ export const locationForNewEnv = (parentFolder: string, projectName: string, env * @param runtimeStartupService The runtime startup service. * @returns The runtime ID of the selected Python interpreter. */ -export const getSelectedPythonInterpreterId = (existingSelection: string | undefined, runtimeStartupService: IRuntimeStartupService) => { - if (existingSelection) { - return existingSelection; - } - const preferredRuntimeId = getPreferredRuntimeId(runtimeStartupService, 'python'); - return preferredRuntimeId ?? ''; +export const getSelectedPythonInterpreterId = ( + existingSelection: string | undefined, + runtimeStartupService: IRuntimeStartupService +) => { + return existingSelection ?? getPreferredRuntimeId(runtimeStartupService, 'python') ?? ''; }; From e0fc632c8da08019a33eba3e874a86ff6f315727 Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 17:13:15 -0400 Subject: [PATCH 7/9] style dropdown entries and use for python interpreters --- .../components/steps/dropdownEntry.css | 29 ++++++++++++++ .../components/steps/dropdownEntry.tsx | 40 +++++++++++++++++++ .../steps/pythonEnvironmentStep.tsx | 4 +- .../steps/pythonInterpreterEntry.tsx | 17 ++++---- 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css create mode 100644 src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.tsx diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css new file mode 100644 index 00000000000..d212e5c1128 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css @@ -0,0 +1,29 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +.dropdown-entry { + display: grid; + grid-template-columns: [icon] min-content [left] max-content [middle] 1fr [right] max-content [end]; + align-items: center; +} + +.dropdown-entry > .dropdown-entry-icon { + grid-column: icon / left; + margin-right: 0.2em; +} + +.dropdown-entry > .dropdown-entry-title { + grid-column: left / middle; +} + +.dropdown-entry > .dropdown-entry-subtitle { + grid-column: middle / right; + font-size: 0.9em; + opacity: 0.7; + margin-left: 0.6em; +} + +.dropdown-entry > .dropdown-entry-group { + grid-column: right / end; +} diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.tsx new file mode 100644 index 00000000000..9ff346c0606 --- /dev/null +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.tsx @@ -0,0 +1,40 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (C) 2024 Posit Software, PBC. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +// CSS. +import 'vs/css!./dropdownEntry'; + +// React. +import * as React from 'react'; + +/** + * DropdownEntryProps interface. + */ +interface DropdownEntryProps { + icon?: string; + title: string; + subtitle: string; + group?: string; +} + +/** + * DropdownEntry component. + * @param props The dropdown entry props. + * @returns The rendered component + */ +export const DropdownEntry = (props: DropdownEntryProps) => { + // Render. + return ( +
+ {props.icon ?
{props.icon}
: null} +
+ {props.title} +
+
+ {props.subtitle} +
+ {props.group ?
{props.group}
: null} +
+ ); +}; diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx index 1da6b54034c..84ed0567ea4 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx @@ -21,6 +21,7 @@ import { RadioButtonItem } from 'vs/workbench/browser/positronComponents/positro import { RadioGroup } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/radioGroup'; import { EnvironmentSetupType, PythonEnvironmentType } from 'vs/workbench/browser/positronNewProjectWizard/interfaces/newProjectWizardEnums'; import { PythonInterpreterEntry } from 'vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry'; +import { DropdownEntry } from 'vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry'; /** * The PythonEnvironmentStep component is specific to Python projects in the new project wizard. @@ -223,8 +224,9 @@ export const PythonEnvironmentStep = (props: PropsWithChildren } onSelectionChanged={dropDownListBoxItem => onEnvTypeSelected(dropDownListBoxItem.options.identifier)} /> : null diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx index 8dd0cf2d12e..4572bd8edf6 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonInterpreterEntry.tsx @@ -10,6 +10,7 @@ import * as React from 'react'; // Other dependencies. import { PythonInterpreterInfo } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils'; +import { DropdownEntry } from 'vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry'; /** * PythonInterpreterEntryProps interface. @@ -26,14 +27,12 @@ interface PythonInterpreterEntryProps { export const PythonInterpreterEntry = ({ pythonInterpreterInfo }: PythonInterpreterEntryProps) => { // Render. return ( -
-
- {/* allow-any-unicode-next-line */} - {`${pythonInterpreterInfo.preferred ? '★ ' : ''}${pythonInterpreterInfo.languageName} ${pythonInterpreterInfo.languageVersion} ${pythonInterpreterInfo.runtimePath}`} -
-
- {pythonInterpreterInfo.runtimeSource} -
-
+ ); }; From 96d01258adb4a28048fb0c8d1800c6c7b23964d0 Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 17:23:04 -0400 Subject: [PATCH 8/9] style the python environment dropdown entries --- .../steps/pythonEnvironmentStep.tsx | 22 +++++-------- .../utilities/pythonEnvironmentStepUtils.ts | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx index 84ed0567ea4..5087e56dc91 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/pythonEnvironmentStep.tsx @@ -12,10 +12,9 @@ import { NewProjectWizardStepProps } from 'vs/workbench/browser/positronNewProje import { localize } from 'vs/nls'; import { RuntimeStartupPhase } from 'vs/workbench/services/runtimeStartup/common/runtimeStartupService'; import { DisposableStore } from 'vs/base/common/lifecycle'; -import { getPythonInterpreterEntries, getSelectedPythonInterpreterId, locationForNewEnv } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils'; +import { getEnvTypeEntries, getPythonInterpreterEntries, getSelectedPythonInterpreterId, locationForNewEnv } from 'vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils'; import { PositronWizardStep } from 'vs/workbench/browser/positronNewProjectWizard/components/wizardStep'; import { PositronWizardSubStep } from 'vs/workbench/browser/positronNewProjectWizard/components/wizardSubStep'; -import { DropDownListBoxItem } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBoxItem'; import { DropDownListBox } from 'vs/workbench/browser/positronComponents/dropDownListBox/dropDownListBox'; import { RadioButtonItem } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/radioButton'; import { RadioGroup } from 'vs/workbench/browser/positronComponents/positronModalDialog/components/radioGroup'; @@ -62,12 +61,7 @@ export const PythonEnvironmentStep = (props: PropsWithChildren } - onSelectionChanged={dropDownListBoxItem => onEnvTypeSelected(dropDownListBoxItem.options.identifier)} + createItem={item => } + onSelectionChanged={item => onEnvTypeSelected(item.options.identifier)} /> : null } @@ -263,11 +257,11 @@ export const PythonEnvironmentStep = (props: PropsWithChildren - + createItem={item => + } - onSelectionChanged={dropDownListBoxItem => - onInterpreterSelected(dropDownListBoxItem.options.identifier) + onSelectionChanged={item => + onInterpreterSelected(item.options.identifier) } /> diff --git a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts index 4bfbba98846..84855414061 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts +++ b/src/vs/workbench/browser/positronNewProjectWizard/utilities/pythonEnvironmentStepUtils.ts @@ -29,6 +29,14 @@ export interface PythonInterpreterInfo { runtimeSource: string; } +/** + * PythonEnvironmentTypeInfo interface. + */ +export interface PythonEnvironmentTypeInfo { + envType: PythonEnvironmentType; + envDescription: string; +} + /** * Retrieves the detected Python interpreters as DropDownListBoxItems, filtering and grouping the * list by runtime source if requested. @@ -201,3 +209,28 @@ export const getSelectedPythonInterpreterId = ( ) => { return existingSelection ?? getPreferredRuntimeId(runtimeStartupService, 'python') ?? ''; }; + +/** + * Constructs and returns the entries for the environment type dropdown box. + * @returns The entries for the environment type dropdown box. + */ +export const getEnvTypeEntries = () => { + // TODO: retrieve the python environment types from the language runtime service somehow? + // TODO: localize these entries + return [ + new DropDownListBoxItem({ + identifier: PythonEnvironmentType.Venv, + value: { + envType: PythonEnvironmentType.Venv, + envDescription: 'Creates a `.venv` virtual environment for your project' + } + }), + new DropDownListBoxItem({ + identifier: PythonEnvironmentType.Conda, + value: { + envType: PythonEnvironmentType.Conda, + envDescription: 'Creates a `.conda` Conda environment for your project' + } + }) + ]; +}; From 95cc0c5f21f187443d7fd936afece9df7abbab47 Mon Sep 17 00:00:00 2001 From: sharon wang Date: Wed, 10 Apr 2024 17:38:40 -0400 Subject: [PATCH 9/9] reduce opacity of dropdown group text --- .../positronNewProjectWizard/components/steps/dropdownEntry.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css index d212e5c1128..e8c1d856f6a 100644 --- a/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css +++ b/src/vs/workbench/browser/positronNewProjectWizard/components/steps/dropdownEntry.css @@ -26,4 +26,5 @@ .dropdown-entry > .dropdown-entry-group { grid-column: right / end; + opacity: 0.8; }