<commit_before>/*
 * Copyright (C) 2017 TypeFox and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 */

import { injectable, inject } from 'inversify';
import { h, VirtualNode } from '@phosphor/virtualdom/lib';
import { DisposableCollection, Disposable } from '@theia/core';
import { VirtualWidget, VirtualRenderer, OpenerService, open, DISABLED_CLASS } from '@theia/core/lib/browser';
import { Extension, ExtensionManager } from '../common';
import { ExtensionUri } from './extension-uri';

@injectable()
export class ExtensionWidget extends VirtualWidget {

    protected extensionStore: Extension[] = [];
    protected readonly updateTimeAfterTyping = 50;
    protected readonly toDisposeOnTypeSearchQuery = new DisposableCollection();
    protected readonly toDisposedOnFetch = new DisposableCollection();
    protected ready = false;

    constructor(
        @inject(ExtensionManager) protected readonly extensionManager: ExtensionManager,
        @inject(OpenerService) protected readonly openerService: OpenerService
    ) {
        super();
        this.id = 'extensions';
        this.title.label = 'Extensions';
        this.addClass('theia-extensions');

        this.fetchExtensions();
    }

    protected onActivateRequest() {
        this.update();
        this.fetchExtensions();
    }

    protected fetchExtensions() {
        this.toDisposedOnFetch.dispose();
        const htmlInputElement = (document.getElementById('extensionSearchField') as HTMLInputElement);
        const searchQuery = htmlInputElement ? htmlInputElement.value : '';
        this.extensionManager.list({
            query: searchQuery
        }).then(extensions => {
            this.extensionStore = extensions;
            extensions.forEach(ext => {
                this.toDisposedOnFetch.push(ext.onDidChange(() => {
                    this.update();
                }));
            });
            this.ready = true;
            this.update();
        });
    }

    protected render(): h.Child {
        if (this.ready) {
            return [this.renderSearchField(), this.renderExtensionList()];
        } else {
            const spinner = h.div({ className: 'fa fa-spinner fa-pulse fa-3x fa-fw' }, '');
            return h.div({ className: 'spinnerContainer' }, spinner);
        }
    }

    protected renderSearchField(): VirtualNode {
        const searchField = h.input({
            id: 'extensionSearchField',
            type: 'text',
            placeholder: 'Search theia extensions',
            onkeyup: event => {
                this.toDisposeOnTypeSearchQuery.dispose();
                const timer = setTimeout(() => this.fetchExtensions(), this.updateTimeAfterTyping);
                this.toDisposeOnTypeSearchQuery.push(Disposable.create(() => clearTimeout(timer)));
            }
        });

        const innerContainer = h.div({
            id: 'extensionSearchFieldContainer',
            className: 'flexcontainer'
        }, [searchField]);

        const container = h.div({
            id: 'extensionSearchContainer',
            className: 'flexcontainer'
        }, [innerContainer]);

        return container;
    }

    protected renderExtensionList(): VirtualNode {
        const theList: h.Child[] = [];
        this.extensionStore.forEach(extension => {
            const container = this.renderExtension(extension);
            theList.push(container);
        });

        return h.div({
            id: 'extensionListContainer'
        },
            VirtualRenderer.flatten(theList));<commit_msg>[extension-ui] filter out transitive extensions if the search query is  empty<commit_after>/*
 * Copyright (C) 2017 TypeFox and others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
 */

import { injectable, inject } from 'inversify';
import { h, VirtualNode } from '@phosphor/virtualdom/lib';
import { DisposableCollection, Disposable } from '@theia/core';
import { VirtualWidget, VirtualRenderer, OpenerService, open, DISABLED_CLASS } from '@theia/core/lib/browser';
import { Extension, ExtensionManager } from '../common';
import { ExtensionUri } from './extension-uri';

@injectable()
export class ExtensionWidget extends VirtualWidget {

    protected extensions: Extension[] = [];
    protected readonly updateTimeAfterTyping = 50;
    protected readonly toDisposeOnTypeSearchQuery = new DisposableCollection();
    protected readonly toDisposedOnFetch = new DisposableCollection();
    protected ready = false;

    constructor(
        @inject(ExtensionManager) protected readonly extensionManager: ExtensionManager,
        @inject(OpenerService) protected readonly openerService: OpenerService
    ) {
        super();
        this.id = 'extensions';
        this.title.label = 'Extensions';
        this.addClass('theia-extensions');

        this.fetchExtensions();
        extensionManager.onDidChange(() => this.fetchExtensions());
    }

    protected onActivateRequest() {
        this.update();
        this.fetchExtensions();
    }

    protected fetchExtensions() {
        this.toDisposedOnFetch.dispose();
        const htmlInputElement = (document.getElementById('extensionSearchField') as HTMLInputElement);
        const searchQuery = htmlInputElement ? htmlInputElement.value.trim() : '';
        this.extensionManager.list({
            query: searchQuery
        }).then(extensions => {
            this.extensions = searchQuery ? extensions : extensions.filter(e => !e.dependent);
            this.ready = true;
            this.update();
        });
    }

    protected render(): h.Child {
        if (this.ready) {
            return [this.renderSearchField(), this.renderExtensionList()];
        } else {
            const spinner = h.div({ className: 'fa fa-spinner fa-pulse fa-3x fa-fw' }, '');
            return h.div({ className: 'spinnerContainer' }, spinner);
        }
    }

    protected renderSearchField(): VirtualNode {
        const searchField = h.input({
            id: 'extensionSearchField',
            type: 'text',
            placeholder: 'Search theia extensions',
            onkeyup: event => {
                this.toDisposeOnTypeSearchQuery.dispose();
                const timer = setTimeout(() => this.fetchExtensions(), this.updateTimeAfterTyping);
                this.toDisposeOnTypeSearchQuery.push(Disposable.create(() => clearTimeout(timer)));
            }
        });

        const innerContainer = h.div({
            id: 'extensionSearchFieldContainer',
            className: 'flexcontainer'
        }, [searchField]);

        const container = h.div({
            id: 'extensionSearchContainer',
            className: 'flexcontainer'
        }, [innerContainer]);

        return container;
    }

    protected renderExtensionList(): VirtualNode {
        const theList: h.Child[] = [];
        this.extensions.forEach(extension => {
            const container = this.renderExtension(extension);
            theList.push(container);
        });

        return h.div({
            id: 'extensionListContainer'
        },
            VirtualRenderer.flatten(theList));
{'fraction_non_alphanumeric': 0.11337990327780763, 'fraction_numerical': 0.002955400322407308, 'mean_word_length': 2.5741718674987997, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4227583', 'n_tokens_mistral': 1884, 'n_tokens_neox': 1820, 'n_words': 457}