Skip to content

Commit a029b0a

Browse files
authored
Use menu title actions instead of PositronActionBar for the Packages pane (#12950)
See #12922 This PR uses the built-in vscode title menu actions instead of the PositronActionBar. The result is that the action buttons appear on the same row as the view's title. This behavior will provide a more native and consistent experience with vscode. This also removes the active session label. Users should use the session picker in the top right to understand the current foreground session. <img width="289" height="147" alt="Screenshot 2026-04-09 at 11 17 48 PM" src="https://github.com/user-attachments/assets/88fa0e1d-c7b7-4bd9-8f66-16bfbffd779c" /> ### QA Notes Behavior should basically be the same as before. @:packages-pane
1 parent e11ed79 commit a029b0a

8 files changed

Lines changed: 211 additions & 269 deletions

File tree

src/vs/workbench/contrib/positronPackages/browser/components/listPackages.tsx

Lines changed: 11 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import './listPackages.css';
99
// React.
1010
import React, {
1111
CSSProperties,
12-
useCallback,
1312
useEffect,
1413
useMemo,
1514
useRef,
@@ -22,31 +21,14 @@ import * as DOM from '../../../../../base/browser/dom.js';
2221
import { isMacintosh } from '../../../../../base/common/platform.js';
2322
import { useStateRef } from '../../../../../base/browser/ui/react/useStateRef.js';
2423
import { positronClassNames } from '../../../../../base/common/positronUtilities.js';
25-
import { ActionBarButton } from '../../../../../platform/positronActionBar/browser/components/actionBarButton.js';
26-
import { ActionBarMenuButton } from '../../../../../platform/positronActionBar/browser/components/actionBarMenuButton.js';
27-
import { ActionBarRegion } from '../../../../../platform/positronActionBar/browser/components/actionBarRegion.js';
28-
import { PositronActionBar } from '../../../../../platform/positronActionBar/browser/positronActionBar.js';
29-
import { PositronActionBarContextProvider } from '../../../../../platform/positronActionBar/browser/positronActionBarContext.js';
3024
import { ViewsProps } from '../positronPackages.js';
3125
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
32-
import { ThemeIcon } from '../../../../../base/common/themables.js';
3326
import { localize } from '../../../../../nls.js';
3427
import { usePositronPackagesContext } from '../positronPackagesContext.js';
35-
import { ILanguageRuntimePackage, ILanguageRuntimeSession } from '../../../../services/runtimeSession/common/runtimeSessionService.js';
28+
import { ILanguageRuntimePackage } from '../../../../services/runtimeSession/common/runtimeSessionService.js';
3629
import { ProgressBar } from '../../../../../base/browser/ui/progressbar/progressbar.js';
3730
import { usePositronReactServicesContext } from '../../../../../base/browser/positronReactRendererContext.js';
3831
import { Separator } from '../../../../../base/common/actions.js';
39-
import { PackagesInstanceMenuButton } from './packagesInstanceMenuButton.js';
40-
41-
const positronRefreshPackages = localize(
42-
'positronRefreshPackages',
43-
'Refresh Packages',
44-
);
45-
46-
const positronInstallPackage = localize(
47-
'positronInstallPackage',
48-
'Install Package',
49-
);
5032

5133
const positronUninstallPackage = localize(
5234
'positronUninstallPackage',
@@ -58,16 +40,6 @@ const positronUpdatePackage = localize(
5840
'Update Package',
5941
);
6042

61-
const positronUpdateAllPackages = localize(
62-
'positronUpdateAllPackages',
63-
'Update All Packages',
64-
);
65-
66-
const positronPackageActions = localize(
67-
'positronPackageActions',
68-
'Package Actions',
69-
);
70-
7143
export const ListPackages = (props: React.PropsWithChildren<ViewsProps>) => {
7244
const {
7345
activeInstance,
@@ -286,10 +258,15 @@ export const ListPackages = (props: React.PropsWithChildren<ViewsProps>) => {
286258
);
287259
};
288260

289-
// Map selected item to package name
290-
const getSelectedItemPackageName = useCallback((item: string | undefined) => {
291-
return deduplicatedPackages.find((pkg) => pkg.id === item)?.name;
292-
}, [deduplicatedPackages]);
261+
// Update selected package in the service when selection changes
262+
useEffect(() => {
263+
// Find the package name from the selected item id
264+
const selectedPackageName = selectedItem
265+
? deduplicatedPackages.find((pkg) => pkg.id === selectedItem)?.name
266+
: undefined;
267+
services.positronPackagesService.setSelectedPackage(selectedPackageName);
268+
return () => services.positronPackagesService.setSelectedPackage(undefined);
269+
}, [selectedItem, deduplicatedPackages, services.positronPackagesService]);
293270

294271
return (
295272
// eslint-disable-next-line jsx-a11y/no-static-element-interactions
@@ -303,29 +280,9 @@ export const ListPackages = (props: React.PropsWithChildren<ViewsProps>) => {
303280
>
304281
<div ref={progressRef} id='packages-progress' />
305282

306-
<ActionBar
307-
activeSession={activeInstance?.session}
308-
busy={loading}
309-
selectedItem={selectedItem}
310-
onInstallPackage={() => services.commandService.executeCommand('positronPackages.installPackage')}
311-
onRefreshPackages={() => services.commandService.executeCommand('positronPackages.refreshPackages')}
312-
onUninstallPackage={() => {
313-
const packageName = getSelectedItemPackageName(selectedItem);
314-
if (packageName) {
315-
services.commandService.executeCommand('positronPackages.uninstallPackage', packageName);
316-
}
317-
}}
318-
onUpdateAllPackages={() => services.commandService.executeCommand('positronPackages.updateAllPackages')}
319-
onUpdatePackage={() => {
320-
const packageName = getSelectedItemPackageName(selectedItem);
321-
if (packageName) {
322-
services.commandService.executeCommand('positronPackages.updatePackage', packageName);
323-
}
324-
}}
325-
></ActionBar>
326283
<div className='packages-list-container'>
327284
<List
328-
height={height - ACTION_BAR_HEIGHT}
285+
height={height}
329286
innerRef={innerRef}
330287
itemCount={deduplicatedPackages.length}
331288
itemKey={(index) => deduplicatedPackages[index].id}
@@ -338,99 +295,3 @@ export const ListPackages = (props: React.PropsWithChildren<ViewsProps>) => {
338295
</div >
339296
);
340297
};
341-
342-
const ACTION_BAR_PADDING_LEFT = 8;
343-
const ACTION_BAR_PADDING_RIGHT = 8;
344-
const ACTION_BAR_HEIGHT = 28;
345-
346-
interface ActionBarProps {
347-
busy: boolean;
348-
activeSession?: ILanguageRuntimeSession;
349-
selectedItem?: string;
350-
onInstallPackage: () => void;
351-
onRefreshPackages: () => void;
352-
onUninstallPackage: () => void;
353-
onUpdateAllPackages: () => void;
354-
onUpdatePackage: () => void;
355-
}
356-
357-
const ActionBar = ({
358-
busy,
359-
activeSession,
360-
selectedItem,
361-
onInstallPackage,
362-
onRefreshPackages,
363-
onUpdateAllPackages,
364-
onUpdatePackage,
365-
onUninstallPackage,
366-
...props
367-
}: React.PropsWithChildren<ActionBarProps>) => {
368-
return (
369-
<div style={{ height: ACTION_BAR_HEIGHT }}>
370-
<PositronActionBarContextProvider {...props}>
371-
<PositronActionBar
372-
borderBottom={true}
373-
borderTop={true}
374-
paddingLeft={ACTION_BAR_PADDING_LEFT}
375-
paddingRight={ACTION_BAR_PADDING_RIGHT}
376-
>
377-
<ActionBarRegion location='left'>
378-
<PackagesInstanceMenuButton />
379-
</ActionBarRegion>
380-
<ActionBarRegion location='right'>
381-
<ActionBarButton
382-
align='right'
383-
ariaLabel={positronRefreshPackages}
384-
disabled={busy || !activeSession}
385-
icon={ThemeIcon.fromId('refresh')}
386-
tooltip={positronRefreshPackages}
387-
onPressed={onRefreshPackages}
388-
/>
389-
<ActionBarMenuButton
390-
actions={() => [
391-
{
392-
id: 'positron.packages.installPackage',
393-
label: positronInstallPackage,
394-
tooltip: positronInstallPackage,
395-
class: undefined,
396-
enabled: !busy,
397-
run: onInstallPackage,
398-
},
399-
{
400-
id: 'positron.packages.updateAllPackages',
401-
label: positronUpdateAllPackages,
402-
tooltip: positronUpdateAllPackages,
403-
class: undefined,
404-
enabled: !busy,
405-
run: onUpdateAllPackages,
406-
},
407-
{
408-
id: 'positron.packages.updatePackage',
409-
label: positronUpdatePackage,
410-
tooltip: positronUpdatePackage,
411-
class: undefined,
412-
enabled: !busy && Boolean(selectedItem),
413-
run: onUpdatePackage,
414-
},
415-
{
416-
id: 'positron.packages.uninstallPackage',
417-
label: positronUninstallPackage,
418-
tooltip: positronUninstallPackage,
419-
class: undefined,
420-
enabled: !busy && Boolean(selectedItem),
421-
run: onUninstallPackage,
422-
},
423-
]}
424-
align='right'
425-
ariaLabel={positronPackageActions}
426-
disabled={!activeSession}
427-
dropdownIndicator='disabled'
428-
icon={ThemeIcon.fromId('ellipsis')}
429-
tooltip={positronPackageActions}
430-
/>
431-
</ActionBarRegion>
432-
</PositronActionBar>
433-
</PositronActionBarContextProvider>
434-
</div>
435-
);
436-
};

src/vs/workbench/contrib/positronPackages/browser/components/packagesInstanceMenuButton.tsx

Lines changed: 0 additions & 64 deletions
This file was deleted.

src/vs/workbench/contrib/positronPackages/browser/interfaces/positronPackagesService.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ export interface IPositronPackagesService {
2525

2626
readonly activePackagesInstance: IPositronPackagesInstance | undefined;
2727

28+
/**
29+
* The currently selected package name in the packages view, if any.
30+
*/
31+
readonly selectedPackage: string | undefined;
32+
33+
/**
34+
* Sets the currently selected package.
35+
* @param packageName The package name, or undefined to clear selection
36+
*/
37+
setSelectedPackage(packageName: string | undefined): void;
38+
2839
/**
2940
* The onDidRefreshPackagesInstance event.
3041
*/

0 commit comments

Comments
 (0)