Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,18 @@ workbenchRegistry.registerWorkbenchContribution(MissingPackagesPrecomputeContrib
workbenchRegistry.registerWorkbenchContribution(MissingPackagesContextKeyContribution, LifecyclePhase.Restored);

// Editor action bar badge (scenario 2) for scripts whose language has a session
// that supports missing packages, and Quarto documents. The editor action bar
// is disabled for notebooks, so notebooks get a separate mount below. Quarto
// documents are multi-language; the service splits them into per-language code
// chunks and routes each to its session.
// that supports missing packages, and Quarto documents. The Positron notebook
// toolbar also renders this menu, so notebooks are excluded here and get their
// own mount below. Quarto documents are multi-language; the service splits them
// into per-language code chunks and routes each to its session.
PositronActionBarWidgetRegistry.registerWidget({
id: 'positronMissingPackages.editorBadge',
menuId: MenuId.EditorActionsRight,
order: 95,
when: MISSING_PACKAGES_SUPPORTED_KEY,
when: ContextKeyExpr.and(
MISSING_PACKAGES_SUPPORTED_KEY,
ContextKeyExpr.notEquals('activeEditor', POSITRON_NOTEBOOK_EDITOR_ID),
),
selfContained: true,
componentFactory: (accessor) => () => React.createElement(MissingPackagesBadgeMount, { accessor }),
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (C) 2026 Posit Software, PBC. All rights reserved.
* Licensed under the Elastic License 2.0. See LICENSE.txt for license information.
*--------------------------------------------------------------------------------------------*/

/// <reference types="vitest/globals" />

import { MenuId } from '../../../../../platform/actions/common/actions.js';
import { IContextKeyService } from '../../../../../platform/contextkey/common/contextkey.js';
import { PositronActionBarWidgetRegistry } from '../../../../../platform/positronActionBar/browser/positronActionBarWidgetRegistry.js';
import { stubInterface } from '../../../../../test/vitest/stubInterface.js';
import { POSITRON_NOTEBOOK_EDITOR_ID } from '../../../positronNotebook/common/positronNotebookCommon.js';
import { MISSING_PACKAGES_SUPPORTED_KEY } from '../../browser/missingPackagesContextKey.js';
// Registers the badge widgets as a side effect.
import '../../browser/positronMissingPackages.contribution.js';

function badgesFor(activeEditor: string): string[] {
const values: Record<string, unknown> = {
activeEditor,
[MISSING_PACKAGES_SUPPORTED_KEY.key]: true,
};
const contextKeyService = stubInterface<IContextKeyService>({
contextMatchesRules: rules => !rules || rules.evaluate({ getValue: <T>(key: string) => values[key] as T }),
});
return PositronActionBarWidgetRegistry.getWidgets(MenuId.EditorActionsRight, contextKeyService)
.map(w => w.id)
.filter(id => id.startsWith('positronMissingPackages.'));
}

describe('missing packages badge registration', () => {
it('shows only the notebook badge in a Positron notebook', () => {
expect(badgesFor(POSITRON_NOTEBOOK_EDITOR_ID)).toEqual(['positronMissingPackages.notebookBadge']);
});

it('shows only the editor badge in a text editor', () => {
expect(badgesFor('workbench.editors.files.textFileEditor')).toEqual(['positronMissingPackages.editorBadge']);
});
});
Loading