Skip to content

Commit dca0d07

Browse files
authored
feat: collapse unused section of launch configuration dropdown (#1806)
This PR collapses the "detected" or "custom" section of launch configuration depending on which one is currently selected this should improve a user experience for users that have a lot of custom configurations and the "detected" section is cluttering their already large selection. Moreover for the first setup we select the custom configuration if exists: ```js // Otherwise, return the first launch config or a default one if (this._launchConfigurations.length > 0) { return this._launchConfigurations[0]; } ``` so for enterprise projects with already existing configurations the user should never have a need to expand the "detected" section ### How Has This Been Tested: https://github.com/user-attachments/assets/0d3a21b0-b821-4e83-aedd-ccb58e97e2d6 ### How Has This Change Been Documented: nah
1 parent d2e0643 commit dca0d07

File tree

2 files changed

+72
-25
lines changed

2 files changed

+72
-25
lines changed

packages/vscode-extension/src/webview/components/AppRootSelect.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@
6666
user-select: none;
6767
}
6868

69+
.approot-select-label-collapsible {
70+
cursor: pointer;
71+
display: flex;
72+
align-items: center;
73+
gap: 6px;
74+
}
75+
6976
.approot-select-item {
7077
height: 32px;
7178
line-height: 1.2;

packages/vscode-extension/src/webview/components/AppRootSelect.tsx

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as Select from "@radix-ui/react-select";
22
import "./AppRootSelect.css";
33
import "./shared/Dropdown.css";
44
import _ from "lodash";
5-
import React, { PropsWithChildren, useEffect, useMemo } from "react";
5+
import React, { PropsWithChildren, useEffect, useMemo, useState } from "react";
66
import { use$ } from "@legendapp/state/react";
77
import { useProject } from "../providers/ProjectProvider";
88
import { LaunchConfiguration, LaunchConfigurationKind } from "../../common/LaunchConfig";
@@ -46,6 +46,8 @@ function renderLaunchConfigurations(
4646
prefix: string,
4747
customLaunchConfigurations: LaunchConfiguration[],
4848
selectedValue: string | undefined,
49+
isExpanded: boolean,
50+
onToggleExpand: () => void,
4951
onEditConfig?: (config: LaunchConfiguration, isSelected: boolean) => void
5052
) {
5153
if (customLaunchConfigurations.length === 0) {
@@ -54,33 +56,41 @@ function renderLaunchConfigurations(
5456

5557
return (
5658
<Select.Group>
57-
<Select.Label className="approot-select-label">{groupLabel}</Select.Label>
58-
{customLaunchConfigurations.map((config, idx) => (
59-
<RichSelectItem
60-
value={`${prefix}:${idx}`}
61-
key={idx}
62-
data-testid={`approot-select-item-${config.name || config.appRoot}`}
63-
icon={<span className="codicon codicon-folder" />}
64-
title={displayNameForConfig(config) ?? config.appRoot ?? "./"}
65-
subtitle={displayNameForConfig(config) ? config.appRoot : undefined}
66-
isSelected={selectedValue === `${prefix}:${idx}`}>
67-
{onEditConfig && (
68-
<ConfigureButton
69-
dataTest={`edit-launch-config-button-${config.name || idx}`}
70-
onClick={() =>
71-
onEditConfig(config as LaunchConfiguration, selectedValue === `${prefix}:${idx}`)
72-
}
73-
/>
74-
)}
75-
</RichSelectItem>
76-
))}
59+
<div className="approot-select-label-collapsible" onClick={onToggleExpand}>
60+
<span
61+
className={`codicon ${isExpanded ? "codicon-chevron-down" : "codicon-chevron-right"}`}
62+
/>
63+
<Select.Label className="approot-select-label">{groupLabel}</Select.Label>
64+
</div>
65+
{isExpanded &&
66+
customLaunchConfigurations.map((config, idx) => (
67+
<RichSelectItem
68+
value={`${prefix}:${idx}`}
69+
key={idx}
70+
data-testid={`approot-select-item-${config.name || config.appRoot}`}
71+
icon={<span className="codicon codicon-folder" />}
72+
title={displayNameForConfig(config) ?? config.appRoot ?? "./"}
73+
subtitle={displayNameForConfig(config) ? config.appRoot : undefined}
74+
isSelected={selectedValue === `${prefix}:${idx}`}>
75+
{onEditConfig && (
76+
<ConfigureButton
77+
dataTest={`edit-launch-config-button-${config.name || idx}`}
78+
onClick={() =>
79+
onEditConfig(config as LaunchConfiguration, selectedValue === `${prefix}:${idx}`)
80+
}
81+
/>
82+
)}
83+
</RichSelectItem>
84+
))}
7785
</Select.Group>
7886
);
7987
}
8088

8189
function renderDetectedLaunchConfigurations(
8290
detectedConfigurations: LaunchConfiguration[],
83-
selectedValue: string | undefined
91+
selectedValue: string | undefined,
92+
isExpanded: boolean,
93+
onToggleExpand: () => void
8494
) {
8595
if (detectedConfigurations.length === 0) {
8696
return null;
@@ -90,13 +100,17 @@ function renderDetectedLaunchConfigurations(
90100
"Detected applications",
91101
"detected",
92102
detectedConfigurations,
93-
selectedValue
103+
selectedValue,
104+
isExpanded,
105+
onToggleExpand
94106
);
95107
}
96108

97109
function renderCustomLaunchConfigurations(
98110
customLaunchConfigurations: LaunchConfiguration[],
99111
selectedValue: string | undefined,
112+
isExpanded: boolean,
113+
onToggleExpand: () => void,
100114
onEditConfig: (config: LaunchConfiguration, isSelected: boolean) => void
101115
) {
102116
if (customLaunchConfigurations.length === 0) {
@@ -108,6 +122,8 @@ function renderCustomLaunchConfigurations(
108122
"custom",
109123
customLaunchConfigurations,
110124
selectedValue,
125+
isExpanded,
126+
onToggleExpand,
111127
onEditConfig
112128
);
113129
}
@@ -149,6 +165,11 @@ function AppRootSelect() {
149165
const selectedAppRoot = applicationRoots.find((root) => root.path === selectedAppRootPath);
150166
const { openModal } = useModal();
151167

168+
const [expandedSections, setExpandedSections] = useState<{ detected: boolean; custom: boolean }>({
169+
detected: false,
170+
custom: false,
171+
});
172+
152173
function onEditConfig(config: LaunchConfiguration, isSelected: boolean) {
153174
openModal(<LaunchConfigurationView launchConfig={config} isCurrentConfig={isSelected} />, {
154175
title: "Launch Configuration",
@@ -199,6 +220,14 @@ function AppRootSelect() {
199220
}
200221
})();
201222

223+
useEffect(() => {
224+
if (!projectInitialized) return;
225+
setExpandedSections({
226+
detected: selectedConfiguration.kind === LaunchConfigurationKind.Detected,
227+
custom: selectedConfiguration.kind === LaunchConfigurationKind.Custom,
228+
});
229+
}, [projectInitialized, selectedConfiguration.kind]);
230+
202231
useUnknownConfigurationAlert(projectInitialized && selectedValue === "unknown");
203232

204233
const configurationsCount = detectedConfigurations.length + customConfigurations.length;
@@ -232,8 +261,19 @@ function AppRootSelect() {
232261
<span className="codicon codicon-chevron-up" />
233262
</Select.ScrollUpButton>
234263
<Select.Viewport className="approot-select-viewport">
235-
{renderDetectedLaunchConfigurations(detectedConfigurations, selectedValue)}
236-
{renderCustomLaunchConfigurations(customConfigurations, selectedValue, onEditConfig)}
264+
{renderDetectedLaunchConfigurations(
265+
detectedConfigurations,
266+
selectedValue,
267+
expandedSections.detected,
268+
() => setExpandedSections((prev) => ({ ...prev, detected: !prev.detected }))
269+
)}
270+
{renderCustomLaunchConfigurations(
271+
customConfigurations,
272+
selectedValue,
273+
expandedSections.custom,
274+
() => setExpandedSections((prev) => ({ ...prev, custom: !prev.custom })),
275+
onEditConfig
276+
)}
237277
{configurationsCount > 0 && <Select.Separator className="approot-select-separator" />}
238278
<SelectItem value="manage" data-testid="add-launch-config-button">
239279
<span className="codicon codicon-add" />

0 commit comments

Comments
 (0)