deploy: current vibn theia state
Some checks failed
Playwright Tests / Playwright Tests (ubuntu-22.04, Node.js 22.x) (push) Has been cancelled
3PP License Check / 3PP License Check (11, 22.x, ubuntu-22.04) (push) Has been cancelled
Publish packages to NPM / Perform Publishing (push) Has been cancelled

Made-with: Cursor
This commit is contained in:
2026-02-27 12:01:08 -08:00
commit 8bb5110148
3782 changed files with 640947 additions and 0 deletions

View File

@@ -0,0 +1,10 @@
/** @type {import('eslint').Linter.Config} */
module.exports = {
extends: [
'../../configs/build.eslintrc.json'
],
parserOptions: {
tsconfigRootDir: __dirname,
project: 'tsconfig.json'
}
};

View File

@@ -0,0 +1,42 @@
<div align='center'>
<br />
<img src='https://raw.githubusercontent.com/eclipse-theia/theia/master/logo/theia.svg?sanitize=true' alt='theia-ext-logo' width='100px' />
<h2>ECLIPSE THEIA - PROPERTY-VIEW EXTENSION</h2>
<hr />
</div>
## Description
The `@theia/property-view` extension contributes a generic, global property view based on Theia's global selection.
The property view widget can be opened/toggled either via menu _View->Properties_ or via shortcut <kbd>Shift+Alt+P</kbd>. It is located in the bottom dock area by default.
The following two default content widgets are implemented in this extension:
- EmptyPropertyViewWidget: If no other widget can be provided, a simple message (_No properties available_) is shown.
- ResourcePropertyViewWidget: Can handle `FileSelection`s and `Navigatable` selections (which provide their resource URI) and displays the general `FileStat` information (e.g. location, name, last modified) in a TreeWidget.
To contribute a specific property view, it is necessary to implement a `PropertyViewDataService` which gathers the property data for a selection as well as a `PropertyViewWidgetProvider` which provides a suitable content widget to display the property data for a specific selection inside the property view widget.
</br>
## Additional Information
- [API documentation for `@theia/property-view`](https://eclipse-theia.github.io/theia/docs/next/modules/_theia_property-view.html)
- [Theia - GitHub](https://github.com/eclipse-theia/theia)
- [Theia - Website](https://theia-ide.org/)
## License
- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/)
- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp)
## Trademark
"Theia" is a trademark of the Eclipse Foundation
<https://www.eclipse.org/theia>

View File

@@ -0,0 +1,49 @@
{
"name": "@theia/property-view",
"version": "1.68.0",
"description": "Theia - Property View Extension",
"dependencies": {
"@theia/core": "1.68.0",
"@theia/filesystem": "1.68.0",
"tslib": "^2.6.2"
},
"publishConfig": {
"access": "public"
},
"theiaExtensions": [
{
"frontend": "lib/browser/property-view-frontend-module"
}
],
"keywords": [
"theia-extension"
],
"license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0",
"repository": {
"type": "git",
"url": "https://github.com/eclipse-theia/theia.git"
},
"bugs": {
"url": "https://github.com/eclipse-theia/theia/issues"
},
"homepage": "https://github.com/eclipse-theia/theia",
"files": [
"lib",
"src"
],
"scripts": {
"build": "theiaext build",
"clean": "theiaext clean",
"compile": "theiaext compile",
"lint": "theiaext lint",
"test": "theiaext test",
"watch": "theiaext watch"
},
"devDependencies": {
"@theia/ext-scripts": "1.68.0"
},
"nyc": {
"extends": "../../configs/nyc.json"
},
"gitHead": "21358137e41342742707f660b8e222f940a27652"
}

View File

@@ -0,0 +1,83 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { nls } from '@theia/core/lib/common/nls';
import { ReactWidget } from '@theia/core/lib/browser';
import { injectable } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { PropertyViewContentWidget } from './property-view-content-widget';
import { DefaultPropertyViewWidgetProvider } from './property-view-widget-provider';
/**
* Property view widget that is shown if no property data or selection is available.
* This widget is provided by the {@link EmptyPropertyViewWidgetProvider}.
*/
class EmptyPropertyViewWidget extends ReactWidget implements PropertyViewContentWidget {
static readonly ID = 'theia-empty-property-view';
static readonly LABEL = 'No Properties';
constructor() {
super();
this.id = EmptyPropertyViewWidget.ID;
this.title.label = EmptyPropertyViewWidget.LABEL;
this.title.caption = EmptyPropertyViewWidget.LABEL;
this.title.closable = false;
this.node.tabIndex = 0;
}
updatePropertyViewContent(): void {
this.update();
}
protected render(): React.ReactNode {
return this.emptyComponent;
}
protected emptyComponent: JSX.Element = <div className={'theia-widget-noInfo'}>{nls.localize('theia/property-view/noProperties', 'No properties available.')}</div>;
}
/**
* `EmptyPropertyViewWidgetProvider` is implemented to provide the {@link EmptyPropertyViewWidget}
* if the given selection is undefined or no other provider can handle the given selection.
*/
@injectable()
export class EmptyPropertyViewWidgetProvider extends DefaultPropertyViewWidgetProvider {
static readonly ID = 'no-properties';
override readonly id = EmptyPropertyViewWidgetProvider.ID;
override readonly label = 'DefaultPropertyViewWidgetProvider';
private emptyWidget: EmptyPropertyViewWidget;
constructor() {
super();
this.emptyWidget = new EmptyPropertyViewWidget();
}
override canHandle(selection: Object | undefined): number {
return selection === undefined ? 1 : 0;
}
override provideWidget(selection: Object | undefined): Promise<EmptyPropertyViewWidget> {
return Promise.resolve(this.emptyWidget);
}
override updateContentWidget(selection: Object | undefined): void {
this.emptyWidget.updatePropertyViewContent();
}
}

View File

@@ -0,0 +1,48 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
export const PropertyDataService = Symbol('PropertyDataService');
/**
* `PropertyDataService` should be implemented to provide property data for the given selection.
*/
export interface PropertyDataService {
/**
* A unique id for this provider.
*/
readonly id: string;
/**
* A human-readable name for this provider.
*/
readonly label?: string;
/**
* Test whether this provider can provide property data for the given selection.
* Return a nonzero number if this provider can provide; otherwise it cannot.
* Never reject.
*
* A returned value indicating a priority of this provider.
*/
canHandleSelection(selection: Object | undefined): number;
/**
* Provide property data for the given selection.
* Resolve to a property view content widget.
* Never reject if `canHandle` returns a positive number; otherwise should reject.
*/
providePropertyData(selection: Object | undefined): Promise<Object | undefined>;
}

View File

@@ -0,0 +1,27 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { Widget } from '@theia/core/lib/browser/widgets/widget';
import { PropertyDataService } from './property-data-service';
/**
* A widget that fetches the property data via the given {@link PropertyDataService} and the given selection
* and renders that property data.
* This widget can be provided by a registered `PropertyViewWidgetProvider`.
*/
export interface PropertyViewContentWidget extends Widget {
updatePropertyViewContent(propertyDataService?: PropertyDataService, selection?: Object): void;
}

View File

@@ -0,0 +1,36 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution';
import { injectable } from '@theia/core/shared/inversify';
import { PropertyViewWidget } from './property-view-widget';
@injectable()
export class PropertyViewContribution extends AbstractViewContribution<PropertyViewWidget> {
constructor() {
super({
widgetId: PropertyViewWidget.ID,
widgetName: PropertyViewWidget.LABEL,
defaultWidgetOptions: {
area: 'bottom'
},
toggleCommandId: 'property-view:toggle',
toggleKeybinding: 'shift+alt+p'
});
}
}

View File

@@ -0,0 +1,47 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { bindViewContribution, WidgetFactory } from '@theia/core/lib/browser';
import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider';
import { ContainerModule } from '@theia/core/shared/inversify';
import { EmptyPropertyViewWidgetProvider } from './empty-property-view-widget-provider';
import { PropertyDataService } from './property-data-service';
import { PropertyViewContribution } from './property-view-contribution';
import { PropertyViewService } from './property-view-service';
import { PropertyViewWidget } from './property-view-widget';
import { PropertyViewWidgetProvider } from './property-view-widget-provider';
import { bindResourcePropertyView } from './resource-property-view';
import '../../src/browser/style/property-view.css';
export default new ContainerModule(bind => {
bind(PropertyViewService).toSelf().inSingletonScope();
bindContributionProvider(bind, PropertyDataService);
bindContributionProvider(bind, PropertyViewWidgetProvider);
bind(EmptyPropertyViewWidgetProvider).toSelf().inSingletonScope();
bind(PropertyViewWidgetProvider).to(EmptyPropertyViewWidgetProvider);
bind(PropertyViewWidget).toSelf();
bind(WidgetFactory).toDynamicValue(({ container }) => ({
id: PropertyViewWidget.ID,
createWidget: () => container.get(PropertyViewWidget)
})).inSingletonScope();
bindViewContribution(bind, PropertyViewContribution);
bindResourcePropertyView(bind);
});

View File

@@ -0,0 +1,62 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { ContributionProvider, Prioritizeable } from '@theia/core';
import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
import { EmptyPropertyViewWidgetProvider } from './empty-property-view-widget-provider';
import { PropertyViewWidgetProvider } from './property-view-widget-provider';
/**
* `PropertyViewService` provides an access to existing property view widget providers.
*/
@injectable()
export class PropertyViewService {
@inject(ContributionProvider) @named(PropertyViewWidgetProvider)
private readonly contributions: ContributionProvider<PropertyViewWidgetProvider>;
@inject(EmptyPropertyViewWidgetProvider)
private readonly emptyWidgetProvider: EmptyPropertyViewWidgetProvider;
private providers: PropertyViewWidgetProvider[] = [];
@postConstruct()
init(): void {
this.providers = this.providers.concat(this.contributions.getContributions());
}
/**
* Return a property view widget provider with the highest priority for the given selection.
* Never reject, return the default provider ({@link EmptyPropertyViewWidgetProvider};
* displays `No properties available`) if there are no other matches.
*/
async getProvider(selection: Object | undefined): Promise<PropertyViewWidgetProvider> {
const provider = await this.prioritize(selection);
return provider ?? this.emptyWidgetProvider;
}
protected async prioritize(selection: Object | undefined): Promise<PropertyViewWidgetProvider | undefined> {
const prioritized = await Prioritizeable.prioritizeAll(this.providers, async (provider: PropertyViewWidgetProvider) => {
try {
return await provider.canHandle(selection);
} catch {
return 0;
}
});
return prioritized.length !== 0 ? prioritized[0].value : undefined;
}
}

View File

@@ -0,0 +1,112 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { ContributionProvider, MaybePromise, Prioritizeable } from '@theia/core';
import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
import { PropertyDataService } from './property-data-service';
import { PropertyViewContentWidget } from './property-view-content-widget';
export const PropertyViewWidgetProvider = Symbol('PropertyViewWidgetProvider');
/**
* The `PropertyViewWidgetProvider` should be implemented to provide a property view content widget for the given selection..
*/
export interface PropertyViewWidgetProvider {
/**
* A unique id for this provider.
*/
id: string;
/**
* A human-readable name for this provider.
*/
label?: string;
/**
* Test whether this provider can provide a widget for the given selection.
* A returned value indicating a priority of this provider.
*
* @param selection the global selection object
* @returns a nonzero number if this provider can provide; otherwise it cannot; never reject
*/
canHandle(selection: Object | undefined): MaybePromise<number>;
/**
* Provide a widget for the given selection.
* Never reject if `canHandle` return a positive number; otherwise should reject.
*
* @param selection the global selection object
* @returns a resolved property view content widget.
*/
provideWidget(selection: Object | undefined): Promise<PropertyViewContentWidget>;
/**
* Update the widget with the given selection.
* Never reject if `canHandle` return a positive number; otherwise should reject.
*
* @param selection the global selection object
* @returns a resolved property view content widget.
*/
updateContentWidget(selection: Object | undefined): void;
}
/**
* The `DefaultPropertyViewWidgetProvider` is the default abstract implementation of the {@link PropertyViewWidgetProvider}
* and should be extended to provide a property view content widget for the given selection.
*/
@injectable()
export abstract class DefaultPropertyViewWidgetProvider implements PropertyViewWidgetProvider {
@inject(ContributionProvider) @named(PropertyDataService)
protected readonly contributions: ContributionProvider<PropertyDataService>;
protected propertyDataServices: PropertyDataService[] = [];
id = 'default';
label = 'DefaultPropertyViewWidgetProvider';
@postConstruct()
init(): void {
this.propertyDataServices = this.propertyDataServices.concat(this.contributions.getContributions());
}
canHandle(selection: Object | undefined): MaybePromise<number> {
return 0;
}
provideWidget(selection: Object | undefined): Promise<PropertyViewContentWidget> {
throw new Error('not implemented');
}
updateContentWidget(selection: Object | undefined): void {
// no-op
}
protected async getPropertyDataService(selection: Object | undefined): Promise<PropertyDataService> {
const dataService = await this.prioritize(selection);
return dataService ?? this.propertyDataServices[0];
}
protected async prioritize(selection: Object | undefined): Promise<PropertyDataService | undefined> {
const prioritized = await Prioritizeable.prioritizeAll(this.propertyDataServices, async (service: PropertyDataService) => {
try {
return service.canHandleSelection(selection);
} catch {
return 0;
}
});
return prioritized.length !== 0 ? prioritized[0].value : undefined;
}
}

View File

@@ -0,0 +1,118 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { Message } from '@theia/core/shared/@lumino/messaging';
import { Disposable, SelectionService } from '@theia/core';
import { BaseWidget, codicon, MessageLoop, Widget } from '@theia/core/lib/browser/widgets/widget';
import { DisposableCollection } from '@theia/core/lib/common/disposable';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import { PropertyViewContentWidget } from './property-view-content-widget';
import { PropertyViewService } from './property-view-service';
import { nls } from '@theia/core/lib/common/nls';
/**
* The main container for the selection-specific property widgets.
* Based on the given selection, the registered `PropertyViewWidgetProvider` provides the
* content widget that displays the corresponding properties.
*/
@injectable()
export class PropertyViewWidget extends BaseWidget {
static readonly ID = 'property-view';
static readonly LABEL = nls.localize('theia/property-view/properties', 'Properties');
protected contentWidget: PropertyViewContentWidget;
protected override toDisposeOnDetach = new DisposableCollection();
@inject(PropertyViewService) protected readonly propertyViewService: PropertyViewService;
@inject(SelectionService) protected readonly selectionService: SelectionService;
@postConstruct()
init(): void {
this.id = PropertyViewWidget.ID;
this.title.label = PropertyViewWidget.LABEL;
this.title.caption = PropertyViewWidget.LABEL;
this.title.iconClass = codicon('table');
this.title.closable = true;
this.addClass('theia-property-view-widget');
this.node.tabIndex = 0;
let disposed = false;
this.toDispose.push(Disposable.create(() => disposed = true));
this.toDispose.push(this.selectionService.onSelectionChanged((selection: Object | undefined) => {
this.propertyViewService.getProvider(selection).then(provider => {
provider.provideWidget(selection).then(contentWidget => {
if (!disposed) {
this.replaceContentWidget(contentWidget);
provider.updateContentWidget(selection);
}
});
});
}));
}
protected initializeContentWidget(selection: Object | undefined): void {
this.propertyViewService.getProvider(selection).then(provider => {
provider.provideWidget(selection).then(contentWidget => {
this.attachContentWidget(contentWidget);
provider.updateContentWidget(selection);
});
});
}
protected replaceContentWidget(newContentWidget: PropertyViewContentWidget): void {
if (this.contentWidget.id !== newContentWidget.id) {
if (this.contentWidget) {
Widget.detach(this.contentWidget);
}
this.attachContentWidget(newContentWidget);
}
}
protected attachContentWidget(newContentWidget: PropertyViewContentWidget): void {
this.contentWidget = newContentWidget;
Widget.attach(this.contentWidget, this.node);
this.toDisposeOnDetach = new DisposableCollection();
this.toDisposeOnDetach.push(Disposable.create(() => {
if (this.contentWidget) {
Widget.detach(this.contentWidget);
}
}));
this.update();
}
protected override onAfterAttach(msg: Message): void {
super.onAfterAttach(msg);
this.initializeContentWidget(this.selectionService.selection);
}
protected override onActivateRequest(msg: Message): void {
super.onActivateRequest(msg);
this.node.focus();
if (this.contentWidget) {
this.contentWidget.activate();
}
}
protected override onResize(msg: Widget.ResizeMessage): void {
super.onResize(msg);
if (this.contentWidget) {
MessageLoop.sendMessage(this.contentWidget, msg);
}
}
}

View File

@@ -0,0 +1,17 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
export * from './resource-property-view-tree-container';

View File

@@ -0,0 +1,127 @@
// *****************************************************************************
// Copyright (C) 2021 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
let disableJSDOM = enableJSDOM();
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
FrontendApplicationConfigProvider.set({});
import { expect } from 'chai';
import { Container } from '@theia/core/shared/inversify';
import { ResourcePropertyDataService } from './resource-property-data-service';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import URI from '@theia/core/lib/common/uri';
import { PropertyDataService } from '../property-data-service';
import { FileSelection } from '@theia/filesystem/lib/browser/file-selection';
import { Navigatable } from '@theia/core/lib/browser/navigatable';
import { FileStat } from '@theia/filesystem/lib/common/files';
disableJSDOM();
let resourcePropertyDataService: ResourcePropertyDataService;
const mockFileStat: FileStat = {
isFile: false,
isDirectory: true,
isSymbolicLink: false,
isReadonly: false,
resource: new URI('resource'),
name: 'name'
};
describe('resource-property-data-service', () => {
before(() => {
disableJSDOM = enableJSDOM();
const container = new Container();
container.bind(ResourcePropertyDataService).toSelf().inSingletonScope();
container.bind(FileService).toConstantValue({
async resolve(uri: URI): Promise<FileStat> {
return mockFileStat;
}
} as FileService);
container.bind(PropertyDataService).to(ResourcePropertyDataService).inSingletonScope();
resourcePropertyDataService = container.get(ResourcePropertyDataService);
});
after(() => {
disableJSDOM();
});
const navigatableSelection: Navigatable = {
getResourceUri(): URI | undefined {
return new URI('resource-uri');
},
createMoveToUri(): URI | undefined {
return new URI('move-uri');
}
};
const fileSelection: FileSelection[] = [
{ fileStat: mockFileStat }
];
describe('#canHandle', () => {
it('should not handle an empty object selection', () => {
expect(resourcePropertyDataService.canHandleSelection({})).eq(0);
});
it('should not handle an undefined selection', () => {
expect(resourcePropertyDataService.canHandleSelection(undefined)).eq(0);
});
it('should handle a file selection', () => {
expect(resourcePropertyDataService.canHandleSelection(fileSelection)).to.be.greaterThan(0);
});
it('should handle a navigatable selection', () => {
expect(resourcePropertyDataService.canHandleSelection(navigatableSelection)).to.be.greaterThan(0);
});
});
describe('#providePropertyData', () => {
it('should return the file-stat of a file selection', async () => {
const data = await resourcePropertyDataService.providePropertyData(fileSelection);
expect(data).to.equal(mockFileStat);
});
it('should return the first file-stat for multiple file selections', async () => {
const arrayFileSelection: FileSelection[] = [
{ fileStat: mockFileStat },
{ fileStat: { ...mockFileStat, resource: new URI('secondURI') } }
];
const data = await resourcePropertyDataService.providePropertyData(arrayFileSelection);
expect(data).to.equal(arrayFileSelection[0].fileStat);
});
it('should return the file-stat for a navigatable selection', async () => {
const data = await resourcePropertyDataService.providePropertyData(navigatableSelection);
expect(data).to.equal(mockFileStat);
});
it('should return undefined if the selection is undefined', async () => {
const data = await resourcePropertyDataService.providePropertyData(undefined);
expect(data).to.equal(undefined);
});
});
});

View File

@@ -0,0 +1,64 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { Navigatable } from '@theia/core/lib/browser';
import URI from '@theia/core/lib/common/uri';
import { FileSelection } from '@theia/filesystem/lib/browser/file-selection';
import { FileService } from '@theia/filesystem/lib/browser/file-service';
import { FileStat } from '@theia/filesystem/lib/common/files';
import { inject, injectable } from '@theia/core/shared/inversify';
import { PropertyDataService } from '../property-data-service';
/**
* This data service provides property data for {@link FileSelection}s and selections of {@link Navigatable}s.
*/
@injectable()
export class ResourcePropertyDataService implements PropertyDataService {
readonly id = 'resources';
readonly label = 'ResourcePropertyDataService';
@inject(FileService) protected readonly fileService: FileService;
canHandleSelection(selection: Object | undefined): number {
return (this.isFileSelection(selection) || this.isNavigatableSelection(selection)) ? 1 : 0;
}
protected isFileSelection(selection: Object | undefined): boolean {
return !!selection && Array.isArray(selection) && FileSelection.is(selection[0]);
}
protected isNavigatableSelection(selection: Object | undefined): boolean {
return !!selection && Navigatable.is(selection);
}
protected async getFileStat(uri: URI): Promise<FileStat> {
return this.fileService.resolve(uri);
}
async providePropertyData(selection: Object | undefined): Promise<FileStat | undefined> {
if (this.isFileSelection(selection) && Array.isArray(selection)) {
return this.getFileStat(selection[0].fileStat.resource);
} else if (this.isNavigatableSelection(selection)) {
const navigatableUri = (selection as Navigatable).getResourceUri();
if (navigatableUri) {
return this.getFileStat(navigatableUri);
}
}
return undefined;
}
}

View File

@@ -0,0 +1,153 @@
// *****************************************************************************
// Copyright (C) 2021 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom';
let disableJSDOM = enableJSDOM();
import { expect } from 'chai';
import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider';
FrontendApplicationConfigProvider.set({});
import { Container } from '@theia/core/shared/inversify';
import { TreeNode } from '@theia/core/lib/browser/tree/tree';
import { DEFAULT_INFO_ICON, ResourcePropertiesLabelProvider, } from './resource-property-view-label-provider';
import { LabelProvider, LabelProviderContribution } from '@theia/core/lib/browser/label-provider';
import { ContributionProvider } from '@theia/core/lib/common';
import { ResourcePropertiesCategoryNode, ResourcePropertiesItemNode } from './resource-property-view-tree-items';
disableJSDOM();
let resourcePropertiesLabelProvider: ResourcePropertiesLabelProvider;
describe('resource-property-view-label', () => {
before(() => {
disableJSDOM = enableJSDOM();
const container = new Container();
container.bind(ResourcePropertiesLabelProvider).toSelf().inSingletonScope();
container.bind(LabelProvider).toSelf().inSingletonScope();
container.bind<Partial<ContributionProvider<LabelProviderContribution>>>(ContributionProvider)
.toConstantValue({
getContributions: () => [],
})
.whenTargetNamed(LabelProviderContribution);
resourcePropertiesLabelProvider = container.get(ResourcePropertiesLabelProvider);
});
after(() => {
disableJSDOM();
});
const categoryNode: ResourcePropertiesCategoryNode = {
name: 'category',
id: '',
icon: 'iconCategory',
children: [],
parent: {
id: '',
parent: undefined,
children: []
},
categoryId: '',
expanded: false,
selected: false,
};
const itemNode: ResourcePropertiesItemNode = {
name: 'item',
id: '',
icon: 'iconItem',
selected: false,
parent: {
name: 'category',
id: '',
icon: '',
children: [],
parent: {
id: '',
parent: undefined,
children: []
},
categoryId: '',
expanded: false,
selected: false,
},
property: 'property'
};
describe('#canHandle', () => {
it('should handle a category node', () => {
expect(resourcePropertiesLabelProvider.canHandle(categoryNode)).to.be.greaterThan(0);
});
it('should handle an item node', () => {
expect(resourcePropertiesLabelProvider.canHandle(itemNode)).to.be.greaterThan(0);
});
it('should not handle a tree node (not an item nor a category)', () => {
const node: TreeNode = {
id: '',
parent: undefined
};
expect(resourcePropertiesLabelProvider.canHandle(node)).eq(0);
});
});
describe('#getIcon', () => {
it('should get the icon of a category node', () => {
expect(resourcePropertiesLabelProvider.getIcon(categoryNode)).eq('iconCategory');
});
it('should get the default icon if a category node has an undefined icon field', () => {
const emptyIconCategory: ResourcePropertiesCategoryNode = categoryNode;
emptyIconCategory.icon = undefined;
expect(resourcePropertiesLabelProvider.getIcon(emptyIconCategory)).eq(DEFAULT_INFO_ICON);
});
it('should get the icon of an item node', () => {
expect(resourcePropertiesLabelProvider.getIcon(itemNode)).eq('iconItem');
});
it('should get an empty string if an item node has an undefined icon field', () => {
const emptyIconItem: ResourcePropertiesItemNode = itemNode;
emptyIconItem.icon = undefined;
expect(resourcePropertiesLabelProvider.getIcon(emptyIconItem)).eq('');
});
});
describe('#getName', () => {
it('should get the name of a category node', () => {
expect(resourcePropertiesLabelProvider.getName(categoryNode)).eq('category');
});
it('should get the name of an item node', () => {
expect(resourcePropertiesLabelProvider.getName(itemNode)).eq('item');
});
});
describe('#getLongName', () => {
it('should get the property of an item node', () => {
expect(resourcePropertiesLabelProvider.getLongName(itemNode)).eq('property');
});
it('should get the name of a category node', () => {
expect(resourcePropertiesLabelProvider.getLongName(categoryNode)).eq('category');
});
});
});

View File

@@ -0,0 +1,49 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { codicon, LabelProvider, LabelProviderContribution, TreeNode } from '@theia/core/lib/browser';
import { inject, injectable } from '@theia/core/shared/inversify';
import { ResourcePropertiesCategoryNode, ResourcePropertiesItemNode } from './resource-property-view-tree-items';
export const DEFAULT_INFO_ICON = codicon('info');
@injectable()
export class ResourcePropertiesLabelProvider implements LabelProviderContribution {
@inject(LabelProvider) protected readonly labelProvider: LabelProvider;
canHandle(element: TreeNode): number {
return (ResourcePropertiesCategoryNode.is(element) || ResourcePropertiesItemNode.is(element)) ? 75 : 0;
}
getIcon(node: ResourcePropertiesCategoryNode | ResourcePropertiesItemNode): string {
if (ResourcePropertiesCategoryNode.is(node)) {
return node.icon ?? DEFAULT_INFO_ICON;
}
return node.icon ?? '';
}
getName(node: ResourcePropertiesCategoryNode | ResourcePropertiesItemNode): string {
return node.name;
}
getLongName(node: ResourcePropertiesCategoryNode | ResourcePropertiesItemNode): string {
if (ResourcePropertiesItemNode.is(node)) {
return node.property;
}
return this.getName(node);
}
}

View File

@@ -0,0 +1,47 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { createTreeContainer, LabelProviderContribution, TreeProps } from '@theia/core/lib/browser';
import { interfaces } from '@theia/core/shared/inversify';
import { PropertyDataService } from '../property-data-service';
import { PropertyViewWidgetProvider } from '../property-view-widget-provider';
import { ResourcePropertyDataService } from './resource-property-data-service';
import { ResourcePropertiesLabelProvider } from './resource-property-view-label-provider';
import { ResourcePropertyViewTreeWidget } from './resource-property-view-tree-widget';
import { ResourcePropertyViewWidgetProvider } from './resource-property-view-widget-provider';
const RESOURCE_PROPERTY_VIEW_TREE_PROPS = {
multiSelect: true,
search: true,
} as TreeProps;
function createResourcePropertyViewTreeWidget(parent: interfaces.Container): ResourcePropertyViewTreeWidget {
const child = createTreeContainer(parent, {
props: RESOURCE_PROPERTY_VIEW_TREE_PROPS,
widget: ResourcePropertyViewTreeWidget,
});
return child.get(ResourcePropertyViewTreeWidget);
}
export function bindResourcePropertyView(bind: interfaces.Bind): void {
bind(LabelProviderContribution).to(ResourcePropertiesLabelProvider).inSingletonScope();
bind(PropertyDataService).to(ResourcePropertyDataService).inSingletonScope();
bind(PropertyViewWidgetProvider).to(ResourcePropertyViewWidgetProvider).inSingletonScope();
bind(ResourcePropertyViewTreeWidget).toDynamicValue(ctx =>
createResourcePropertyViewTreeWidget(ctx.container)
);
}

View File

@@ -0,0 +1,53 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { CompositeTreeNode, ExpandableTreeNode, SelectableTreeNode, TreeNode } from '@theia/core/lib/browser';
export const ROOT_ID = 'ResourcePropertiesTree';
export interface ResourcePropertiesRoot extends CompositeTreeNode {
children: ResourcePropertiesCategoryNode[];
}
export namespace ResourcePropertiesRoot {
export function is(node: unknown): node is ResourcePropertiesRoot {
return CompositeTreeNode.is(node) && node.id === ROOT_ID;
}
}
export interface ResourcePropertiesCategoryNode extends ExpandableTreeNode, SelectableTreeNode {
name: string;
icon?: string;
children: ResourcePropertiesItemNode[];
parent: ResourcePropertiesRoot;
categoryId: string;
}
export namespace ResourcePropertiesCategoryNode {
export function is(node: TreeNode | undefined): node is ResourcePropertiesCategoryNode {
return ExpandableTreeNode.is(node) && SelectableTreeNode.is(node) && 'categoryId' in node;
}
}
export interface ResourcePropertiesItemNode extends SelectableTreeNode {
name: string;
icon?: string;
parent: ResourcePropertiesCategoryNode;
property: string;
}
export namespace ResourcePropertiesItemNode {
export function is(node: TreeNode | undefined): node is ResourcePropertiesItemNode {
return !!node && SelectableTreeNode.is(node) && 'property' in node;
}
}

View File

@@ -0,0 +1,219 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import {
ContextMenuRenderer,
NodeProps,
TreeModel,
TreeNode,
TreeProps,
TreeWidget
} from '@theia/core/lib/browser';
import { FileStat } from '@theia/filesystem/lib/common/files';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
import * as React from '@theia/core/shared/react';
import { PropertyDataService } from '../property-data-service';
import { PropertyViewContentWidget } from '../property-view-content-widget';
import {
ResourcePropertiesCategoryNode,
ResourcePropertiesItemNode,
ResourcePropertiesRoot,
ROOT_ID
} from './resource-property-view-tree-items';
import { nls } from '@theia/core/lib/common/nls';
/**
* This widget fetches the property data for {@link FileSelection}s and selections of {@link Navigatable}s
* and renders that property data as a {@link TreeWidget}.
* This widget is provided by the registered `ResourcePropertyViewWidgetProvider`.
*/
@injectable()
export class ResourcePropertyViewTreeWidget extends TreeWidget implements PropertyViewContentWidget {
static readonly ID = 'resource-properties-tree-widget';
static readonly LABEL = 'Resource Properties Tree';
protected propertiesTree: Map<string, ResourcePropertiesCategoryNode>;
protected currentSelection: Object | undefined;
constructor(
@inject(TreeProps) props: TreeProps,
@inject(TreeModel) model: TreeModel,
@inject(ContextMenuRenderer) contextMenuRenderer: ContextMenuRenderer
) {
super(props, model, contextMenuRenderer);
model.root = {
id: ROOT_ID,
name: ResourcePropertyViewTreeWidget.LABEL,
parent: undefined,
visible: false,
children: []
} as ResourcePropertiesRoot;
this.propertiesTree = new Map<string, ResourcePropertiesCategoryNode>();
}
@postConstruct()
protected override init(): void {
super.init();
this.id = ResourcePropertyViewTreeWidget.ID + '-treeContainer';
this.addClass('treeContainer');
this.fillPropertiesTree();
}
protected updateNeeded(selection: Object | undefined): boolean {
return this.currentSelection !== selection;
}
updatePropertyViewContent(propertyDataService?: PropertyDataService, selection?: Object | undefined): void {
if (this.updateNeeded(selection)) {
this.currentSelection = selection;
if (propertyDataService) {
propertyDataService.providePropertyData(selection).then((fileStatObject?: FileStat) => {
this.fillPropertiesTree(fileStatObject);
});
}
}
}
protected fillPropertiesTree(fileStatObject?: FileStat): void {
if (fileStatObject) {
this.propertiesTree.clear();
const infoNode = this.createCategoryNode('info', nls.localizeByDefault('Info'));
this.propertiesTree.set('info', infoNode);
infoNode.children.push(this.createResultLineNode('isDirectory', nls.localize('theia/property-view/directory', 'Directory'), fileStatObject.isDirectory, infoNode));
infoNode.children.push(this.createResultLineNode('isFile', nls.localizeByDefault('File'), fileStatObject.isFile, infoNode));
infoNode.children.push(this.createResultLineNode('isSymbolicLink', nls.localize('theia/property-view/symbolicLink', 'Symbolic link'),
fileStatObject.isSymbolicLink, infoNode));
infoNode.children.push(this.createResultLineNode('location', nls.localize('theia/property-view/location', 'Location'),
this.getLocationString(fileStatObject), infoNode));
infoNode.children.push(this.createResultLineNode('name', nls.localizeByDefault('Name'), this.getFileName(fileStatObject), infoNode));
infoNode.children.push(this.createResultLineNode('path', nls.localizeByDefault('Path'), this.getFilePath(fileStatObject), infoNode));
infoNode.children.push(this.createResultLineNode('lastModification', nls.localize('theia/property-view/lastModified', 'Last modified'),
this.getLastModificationString(fileStatObject), infoNode));
infoNode.children.push(this.createResultLineNode('created', nls.localize('theia/property-view/created', 'Created'),
this.getCreationTimeString(fileStatObject), infoNode));
infoNode.children.push(this.createResultLineNode('size', nls.localizeByDefault('Size'), this.getSizeString(fileStatObject), infoNode));
this.refreshModelChildren();
}
}
protected getLocationString(fileStat: FileStat): string {
return fileStat.resource.path.fsPath();
}
protected getFileName(fileStat: FileStat): string {
return this.labelProvider.getName(fileStat.resource);
}
protected getFilePath(fileStat: FileStat): string {
return this.labelProvider.getLongName(fileStat.resource);
}
protected getLastModificationString(fileStat: FileStat): string {
return fileStat.mtime ? new Date(fileStat.mtime).toLocaleString() : '';
}
protected getCreationTimeString(fileStat: FileStat): string {
return fileStat.ctime ? new Date(fileStat.ctime).toLocaleString() : '';
}
protected getSizeString(fileStat: FileStat): string {
return fileStat.size ? nls.localizeByDefault('{0}B', fileStat.size.toString()) : '';
}
/*
* Creating TreeNodes
*/
protected createCategoryNode(categoryId: string, name: string): ResourcePropertiesCategoryNode {
return {
id: categoryId,
parent: this.model.root as ResourcePropertiesRoot,
name,
children: [],
categoryId,
selected: false,
expanded: true
};
}
protected createResultLineNode(id: string, name: string, property: boolean | string | undefined, parent: ResourcePropertiesCategoryNode): ResourcePropertiesItemNode {
return {
id: `${parent.id}::${id}`,
parent,
name: name,
property: property !== undefined ? String(property) : '',
selected: false
};
}
/**
* Rendering
*/
protected async refreshModelChildren(): Promise<void> {
if (ResourcePropertiesRoot.is(this.model.root)) {
this.model.root.children = Array.from(this.propertiesTree.values());
this.model.refresh();
}
}
protected override renderCaption(node: TreeNode, props: NodeProps): React.ReactNode {
if (ResourcePropertiesCategoryNode.is(node)) {
return this.renderExpandableNode(node);
} else if (ResourcePropertiesItemNode.is(node)) {
return this.renderItemNode(node);
}
return undefined;
}
protected renderExpandableNode(node: ResourcePropertiesCategoryNode): React.ReactNode {
return <React.Fragment>
<div className={`theia-resource-tree-node-icon ${this.toNodeIcon(node)}`}></div>
<div className={'theia-resource-tree-node-name theia-TreeNodeSegment theia-TreeNodeSegmentGrow'}>{this.toNodeName(node)}</div>
</React.Fragment>;
}
protected renderItemNode(node: ResourcePropertiesItemNode): React.ReactNode {
return <React.Fragment>
<div className={`theia-resource-tree-node-icon ${this.toNodeIcon(node)}`}></div>
<div className={'theia-resource-tree-node-name theia-TreeNodeSegment theia-TreeNodeSegmentGrow'}>{this.toNodeName(node)}</div>
<div className={'theia-resource-tree-node-property theia-TreeNodeSegment theia-TreeNodeSegmentGrow'}>{this.toNodeDescription(node)}</div>
</React.Fragment>;
}
protected override createNodeAttributes(node: TreeNode, props: NodeProps): React.Attributes & React.HTMLAttributes<HTMLElement> {
return {
...super.createNodeAttributes(node, props),
title: this.getNodeTooltip(node)
};
}
protected getNodeTooltip(node: TreeNode): string | undefined {
if (ResourcePropertiesCategoryNode.is(node)) {
return this.labelProvider.getName(node);
} else if (ResourcePropertiesItemNode.is(node)) {
return `${this.labelProvider.getName(node)}: ${this.labelProvider.getLongName(node)}`;
}
return undefined;
}
}

View File

@@ -0,0 +1,55 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { Navigatable } from '@theia/core/lib/browser';
import { FileSelection } from '@theia/filesystem/lib/browser/file-selection';
import { inject, injectable } from '@theia/core/shared/inversify';
import { DefaultPropertyViewWidgetProvider } from '../property-view-widget-provider';
import { ResourcePropertyViewTreeWidget } from './resource-property-view-tree-widget';
/**
* Provides the {@link ResourcePropertyViewTreeWidget} for
* {@link FileSelection}s and selections of {@link Navigatable}s.
*/
@injectable()
export class ResourcePropertyViewWidgetProvider extends DefaultPropertyViewWidgetProvider {
@inject(ResourcePropertyViewTreeWidget) protected treeWidget: ResourcePropertyViewTreeWidget;
override readonly id = 'resources';
override readonly label = 'ResourcePropertyViewWidgetProvider';
override canHandle(selection: Object | undefined): number {
return (this.isFileSelection(selection) || this.isNavigatableSelection(selection)) ? 1 : 0;
}
protected isFileSelection(selection: Object | undefined): boolean {
return !!selection && Array.isArray(selection) && FileSelection.is(selection[0]);
}
protected isNavigatableSelection(selection: Object | undefined): boolean {
return !!selection && Navigatable.is(selection);
}
override provideWidget(selection: Object | undefined): Promise<ResourcePropertyViewTreeWidget> {
return Promise.resolve(this.treeWidget);
}
override updateContentWidget(selection: Object | undefined): void {
this.getPropertyDataService(selection).then(service => this.treeWidget.updatePropertyViewContent(service, selection));
}
}

View File

@@ -0,0 +1,51 @@
/********************************************************************************
* Copyright (C) 2020 EclipseSource and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
********************************************************************************/
:root {
--theia-property-view-widget-padding: 5px;
--theia-empty-property-view-widget-padding: 8px;
--theia-resource-tree-node-icon-margin: 0 3px;
--theia-resource-tree-node-icon-flex-basis: 1.5%;
--theia-resource-tree-node-name-flex-basis: 30%;
--theia-resource-tree-node-property-flex-basis: 70%;
}
.theia-property-view-widget {
padding: var(--theia-border-width);
}
#theia-empty-property-view .theia-widget-noInfo {
padding: var(--theia-empty-property-view-widget-padding);
}
.theia-property-view-widget .treeContainer {
height: 100%;
}
.theia-resource-tree-node-icon {
margin: var(--theia-resource-tree-node-icon-margin);
flex-basis: var(--theia-resource-tree-node-icon-flex-basis);
align-self: center;
text-align: center;
}
.theia-resource-tree-node-name {
flex-basis: var(--theia-resource-tree-node-name-flex-basis);
}
.theia-resource-tree-node-property {
flex-basis: var(--theia-resource-tree-node-property-flex-basis);
}

View File

@@ -0,0 +1,29 @@
// *****************************************************************************
// Copyright (C) 2020 EclipseSource and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
/* note: this bogus test file is required so that
we are able to run mocha unit tests on this
package, without having any actual unit tests in it.
This way a coverage report will be generated,
showing 0% coverage, instead of no report.
This file can be removed once we have real unit
tests in place. */
describe('property-view package', () => {
it('support code coverage statistics', () => true);
});

View File

@@ -0,0 +1,19 @@
{
"extends": "../../configs/base.tsconfig",
"compilerOptions": {
"composite": true,
"rootDir": "src",
"outDir": "lib"
},
"include": [
"src"
],
"references": [
{
"path": "../core"
},
{
"path": "../filesystem"
}
]
}