mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
testing: move test filter to action bar
This commit is contained in:
parent
2c19f7fb98
commit
3e55989cca
|
@ -9,11 +9,6 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.test-explorer > .monaco-inputbox {
|
||||
flex-shrink: 0;
|
||||
margin: 4px 12px;
|
||||
}
|
||||
|
||||
.test-explorer > .test-explorer-tree {
|
||||
flex-grow: 1;
|
||||
height: 0px;
|
||||
|
@ -75,3 +70,25 @@
|
|||
.monaco-editor .zone-widget.test-output-peek .zone-widget-container.peekview-widget .peekview-title .filename {
|
||||
max-height: 29px;
|
||||
}
|
||||
|
||||
|
||||
/** -- filter */
|
||||
.testing-filter-action-bar {
|
||||
flex-shrink: 0;
|
||||
margin: 4px 12px;
|
||||
}
|
||||
|
||||
.testing-filter-action-item {
|
||||
display: flex !important;
|
||||
flex-grow: 1;
|
||||
max-width: 400px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.testing-filter-action-bar .testing-filter-action-item {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.testing-filter-action-item .testing-filter-wrapper {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -20,23 +20,25 @@ import { Registry } from 'vs/platform/registry/common/platform';
|
|||
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
|
||||
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, IViewsRegistry, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { testingViewIcon } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { ITestExplorerFilterState, TestExplorerFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
|
||||
import { TestingExplorerView } from 'vs/workbench/contrib/testing/browser/testingExplorerView';
|
||||
import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
|
||||
import { TestingViewPaneContainer } from 'vs/workbench/contrib/testing/browser/testingViewPaneContainer';
|
||||
import { Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { TestIdWithProvider } from 'vs/workbench/contrib/testing/common/testCollection';
|
||||
import { IWorkspaceTestCollectionService, WorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService';
|
||||
import { TestingContentProvider } from 'vs/workbench/contrib/testing/common/testingContentProvider';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
import { ITestResultService, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
import { ITestService } from 'vs/workbench/contrib/testing/common/testService';
|
||||
import { TestService } from 'vs/workbench/contrib/testing/common/testServiceImpl';
|
||||
import { IWorkspaceTestCollectionService, WorkspaceTestCollectionService } from 'vs/workbench/contrib/testing/common/workspaceTestCollectionService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import * as Action from './testExplorerActions';
|
||||
import { ITestResultService, TestResultService } from 'vs/workbench/contrib/testing/common/testResultService';
|
||||
|
||||
registerSingleton(ITestService, TestService);
|
||||
registerSingleton(ITestResultService, TestResultService);
|
||||
registerSingleton(ITestExplorerFilterState, TestExplorerFilterState);
|
||||
registerSingleton(IWorkspaceTestCollectionService, WorkspaceTestCollectionService);
|
||||
|
||||
const viewContainer = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer({
|
||||
|
|
|
@ -3,23 +3,40 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { addStandardDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
|
||||
import { HistoryInputBox } from 'vs/base/browser/ui/inputbox/inputBox';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { Delayer } from 'vs/base/common/async';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { localize } from 'vs/nls';
|
||||
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
|
||||
import { ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget';
|
||||
import { ContextKeyEqualsExpr, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { createDecorator, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { StoredValue } from 'vs/workbench/contrib/testing/common/storedValue';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
|
||||
export interface ITestExplorerFilterState {
|
||||
_serviceBrand: undefined;
|
||||
readonly onDidChange: Event<string>;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export const ITestExplorerFilterState = createDecorator<ITestExplorerFilterState>('testingFilterState');
|
||||
|
||||
export class TestExplorerFilterState implements ITestExplorerFilterState {
|
||||
declare _serviceBrand: undefined;
|
||||
|
||||
export class TestingFilterState {
|
||||
private readonly changeEmitter = new Emitter<string>();
|
||||
private _value = '';
|
||||
|
||||
public readonly onDidChange = this.changeEmitter.event;
|
||||
|
||||
|
@ -33,12 +50,10 @@ export class TestingFilterState {
|
|||
this.changeEmitter.fire(v);
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private _value = '') { }
|
||||
}
|
||||
|
||||
export class TestingExplorerFilter extends Widget {
|
||||
private readonly input: HistoryInputBox;
|
||||
export class TestingExplorerFilter extends BaseActionViewItem {
|
||||
private input!: HistoryInputBox;
|
||||
private readonly history: StoredValue<string[]> = this.instantiationService.createInstance(StoredValue, {
|
||||
key: 'testing.filterHistory',
|
||||
scope: StorageScope.WORKSPACE,
|
||||
|
@ -46,24 +61,33 @@ export class TestingExplorerFilter extends Widget {
|
|||
});
|
||||
|
||||
constructor(
|
||||
container: HTMLElement,
|
||||
private readonly state: TestingFilterState,
|
||||
@IContextViewService contextViewService: IContextViewService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
action: IAction,
|
||||
@ITestExplorerFilterState private readonly state: ITestExplorerFilterState,
|
||||
@IContextViewService private readonly contextViewService: IContextViewService,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
super();
|
||||
super(null, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public render(container: HTMLElement) {
|
||||
container.classList.add('testing-filter-action-item');
|
||||
|
||||
const updateDelayer = this._register(new Delayer<void>(400));
|
||||
const wrapper = dom.$('.testing-filter-wrapper');
|
||||
container.appendChild(wrapper);
|
||||
|
||||
const input = this.input = this._register(instantiationService.createInstance(ContextScopedHistoryInputBox, container, contextViewService, {
|
||||
const input = this.input = this._register(this.instantiationService.createInstance(ContextScopedHistoryInputBox, wrapper, this.contextViewService, {
|
||||
placeholder: localize('testExplorerFilter', "Filter (e.g. text, !exclude)"),
|
||||
history: this.history.get([]),
|
||||
}));
|
||||
input.value = state.value;
|
||||
this._register(attachInputBoxStyler(input, themeService));
|
||||
input.value = this.state.value;
|
||||
this._register(attachInputBoxStyler(input, this.themeService));
|
||||
|
||||
this._register(state.onDidChange(newValue => {
|
||||
this._register(this.state.onDidChange(newValue => {
|
||||
input.value = newValue;
|
||||
}));
|
||||
|
||||
|
@ -72,7 +96,7 @@ export class TestingExplorerFilter extends Widget {
|
|||
this.state.value = input.value;
|
||||
})));
|
||||
|
||||
this._register(addStandardDisposableListener(input.inputElement, EventType.KEY_DOWN, e => {
|
||||
this._register(dom.addStandardDisposableListener(input.inputElement, dom.EventType.KEY_DOWN, e => {
|
||||
if (e.equals(KeyCode.Escape)) {
|
||||
input.value = '';
|
||||
e.stopPropagation();
|
||||
|
@ -100,4 +124,28 @@ export class TestingExplorerFilter extends Widget {
|
|||
this.history.delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public dispose() {
|
||||
this.saveState();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(class extends Action2 {
|
||||
constructor() {
|
||||
super({
|
||||
id: Testing.FilterActionId,
|
||||
title: localize('filter', "Filter"),
|
||||
menu: {
|
||||
id: MenuId.ViewTitle,
|
||||
when: ContextKeyExpr.and(ContextKeyEqualsExpr.create('view', Testing.ExplorerViewId), TestingContextKeys.explorerLocation.isEqualTo(ViewContainerLocation.Panel)),
|
||||
group: 'navigation',
|
||||
order: 1,
|
||||
},
|
||||
});
|
||||
}
|
||||
async run(): Promise<void> { }
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
|
|||
import { ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { ITreeEvent, ITreeFilter, ITreeNode, ITreeRenderer, ITreeSorter, TreeFilterResult, TreeVisibility } from 'vs/base/browser/ui/tree/tree';
|
||||
import { Action, IAction, IActionViewItem } from 'vs/base/common/actions';
|
||||
import { DeferredPromise } from 'vs/base/common/async';
|
||||
import { Color, RGBA } from 'vs/base/common/color';
|
||||
import { throttle } from 'vs/base/common/decorators';
|
||||
|
@ -41,7 +42,7 @@ import { TestRunState } from 'vs/workbench/api/common/extHostTypes';
|
|||
import { IResourceLabel, IResourceLabelOptions, IResourceLabelProps, ResourceLabels } from 'vs/workbench/browser/labels';
|
||||
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
|
||||
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
|
||||
import { IViewDescriptorService } from 'vs/workbench/common/views';
|
||||
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { ITestTreeElement, ITestTreeProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections';
|
||||
import { HierarchicalByLocationProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByLocation';
|
||||
import { HierarchicalByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/hierarchalByName';
|
||||
|
@ -50,7 +51,7 @@ import { StateByLocationProjection } from 'vs/workbench/contrib/testing/browser/
|
|||
import { StateByNameProjection } from 'vs/workbench/contrib/testing/browser/explorerProjections/stateByName';
|
||||
import { StateElement } from 'vs/workbench/contrib/testing/browser/explorerProjections/stateNodes';
|
||||
import { testingStatesToIcons } from 'vs/workbench/contrib/testing/browser/icons';
|
||||
import { TestingExplorerFilter, TestingFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
|
||||
import { ITestExplorerFilterState, TestingExplorerFilter, TestExplorerFilterState } from 'vs/workbench/contrib/testing/browser/testingExplorerFilter';
|
||||
import { TestingOutputPeekController } from 'vs/workbench/contrib/testing/browser/testingOutputPeek';
|
||||
import { TestExplorerViewGrouping, TestExplorerViewMode, Testing } from 'vs/workbench/contrib/testing/common/constants';
|
||||
import { TestingContextKeys } from 'vs/workbench/contrib/testing/common/testingContextKeys';
|
||||
|
@ -64,11 +65,11 @@ import { DebugAction, RunAction } from './testExplorerActions';
|
|||
|
||||
export class TestingExplorerView extends ViewPane {
|
||||
public viewModel!: TestingExplorerViewModel;
|
||||
private readonly filterState = new TestingFilterState();
|
||||
private filter!: TestingExplorerFilter;
|
||||
private filterActionBar = this._register(new MutableDisposable());
|
||||
private currentSubscription?: TestSubscriptionListener;
|
||||
private container!: HTMLElement;
|
||||
private finishDiscovery?: () => void;
|
||||
private readonly location = TestingContextKeys.explorerLocation.bindTo(this.contextKeyService);;
|
||||
|
||||
constructor(
|
||||
options: IViewletViewOptions,
|
||||
|
@ -87,6 +88,7 @@ export class TestingExplorerView extends ViewPane {
|
|||
) {
|
||||
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
|
||||
this._register(testService.onDidChangeProviders(() => this._onDidChangeViewWelcomeState.fire()));
|
||||
this.location.set(viewDescriptorService.getViewLocationById(Testing.ExplorerViewId) ?? ViewContainerLocation.Sidebar);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -103,14 +105,16 @@ export class TestingExplorerView extends ViewPane {
|
|||
super.renderBody(container);
|
||||
|
||||
this.container = dom.append(container, dom.$('.test-explorer'));
|
||||
this.filter = this.instantiationService.createInstance(TestingExplorerFilter, this.container, this.filterState);
|
||||
this._register(this.filter);
|
||||
|
||||
if (this.location.get() === ViewContainerLocation.Sidebar) {
|
||||
this.filterActionBar.value = this.createFilterActionBar();
|
||||
}
|
||||
|
||||
const messagesContainer = dom.append(this.container, dom.$('.test-explorer-messages'));
|
||||
this._register(this.instantiationService.createInstance(TestRunProgress, messagesContainer, this.getProgressLocation()));
|
||||
|
||||
const listContainer = dom.append(this.container, dom.$('.test-explorer-tree'));
|
||||
this.viewModel = this.instantiationService.createInstance(TestingExplorerViewModel, listContainer, this.onDidChangeBodyVisibility, this.currentSubscription, this.filterState);
|
||||
this.viewModel = this.instantiationService.createInstance(TestingExplorerViewModel, listContainer, this.onDidChangeBodyVisibility, this.currentSubscription);
|
||||
this._register(this.viewModel);
|
||||
|
||||
this._register(this.onDidChangeBodyVisibility(visible => {
|
||||
|
@ -125,12 +129,29 @@ export class TestingExplorerView extends ViewPane {
|
|||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public getActionViewItem(action: IAction): IActionViewItem | undefined {
|
||||
if (action.id === Testing.FilterActionId) {
|
||||
return this.instantiationService.createInstance(TestingExplorerFilter, action);
|
||||
}
|
||||
|
||||
return super.getActionViewItem(action);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
public saveState() {
|
||||
super.saveState();
|
||||
this.filter.saveState();
|
||||
}
|
||||
|
||||
private createFilterActionBar() {
|
||||
const bar = new ActionBar(this.container, { actionViewItemProvider: action => this.getActionViewItem(action) });
|
||||
bar.push(new Action(Testing.FilterActionId));
|
||||
bar.getContainer().classList.add('testing-filter-action-bar');
|
||||
return bar;
|
||||
}
|
||||
|
||||
private updateDiscoveryProgress(busy: number) {
|
||||
|
@ -205,7 +226,7 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
listContainer: HTMLElement,
|
||||
onDidChangeVisibility: Event<boolean>,
|
||||
private listener: TestSubscriptionListener | undefined,
|
||||
filterState: TestingFilterState,
|
||||
@ITestExplorerFilterState filterState: TestExplorerFilterState,
|
||||
@IInstantiationService instantiationService: IInstantiationService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@ICodeEditorService codeEditorService: ICodeEditorService,
|
||||
|
@ -220,6 +241,7 @@ export class TestingExplorerViewModel extends Disposable {
|
|||
const labels = this._register(instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: onDidChangeVisibility }));
|
||||
|
||||
this.filter = new TestsFilter(filterState.value);
|
||||
|
||||
this._register(filterState.onDidChange(text => {
|
||||
this.filter.setFilter(text);
|
||||
this.tree.refilter();
|
||||
|
|
|
@ -11,6 +11,7 @@ export const enum Testing {
|
|||
ViewletId = 'workbench.view.extension.test',
|
||||
ExplorerViewId = 'workbench.view.testing',
|
||||
OutputPeekContributionId = 'editor.contrib.testingOutputPeek',
|
||||
FilterActionId = 'workbench.actions.treeView.testExplorer.filter',
|
||||
}
|
||||
|
||||
export const enum TestExplorerViewMode {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { TestExplorerViewMode, TestExplorerViewGrouping } from 'vs/workbench/contrib/testing/common/constants';
|
||||
|
||||
export namespace TestingContextKeys {
|
||||
|
@ -12,4 +13,5 @@ export namespace TestingContextKeys {
|
|||
export const viewGrouping = new RawContextKey('testExplorerViewGrouping', TestExplorerViewGrouping.ByLocation);
|
||||
export const isRunning = new RawContextKey('testIsrunning', false);
|
||||
export const peekVisible = new RawContextKey('testPeekVisible', false);
|
||||
export const explorerLocation = new RawContextKey('testExplorerLocation', ViewContainerLocation.Sidebar);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue