The TaskTemplateSelector can not read templates from backend?

Hello:
I’m tring to modify the TaskTemplateSelector to use my own task template (from some JSON file reading by backend). So I created a NewTaskTemplateSelector and rebind(TaskTemplateSelector).to(NewTaskTemplateSelector).

At first, I noticed that Theia create task template in frontend via hard coding,

My NewTaskTemplateSelector is:

export interface TaskConfigServer extends JsonRpcServer<TaskConfigClient> {
    getTaskConfigTemplates(): Promise<TaskTemplateEntry[]>;
}

@injectable()
export class NewTaskTemplateSelector implements FrontendApplicationContribution {
    constructor(
        @inject(TaskConfigServer) protected readonly taskConfigServer: TaskConfigServer,
    ){}

    private templates: TaskTemplateEntry[];

    async initialize(): Promise<void> {
        console.log('NewTaskTemplateSelector.initialize');
        const templates = await this.taskConfigServer.getTaskConfigTemplates();
        if (templates) {
            this.templates = templates;
        }

        console.log('templates: ', templates);
        console.log('this.templates: ', this.templates);
    }

    selectTemplates(): QuickPickValue<TaskTemplateEntry>[] {
        console.log('this.templates', this.templates);
        return this.templates.map(t => ({
            label: t.label,
            description: t.description,
            value: t
        }));
    }
}

The TaskConfigServer is a backend server and it implements the BackendApplicationContribution. Its funtion getTaskConfigTemplates() can return the content of some task template JSON files correctly.

Theia’s TaskTemplateSelector.selectTemplates() is not an async function which means my NewTaskTemplateSelector.selectTemplates() can not be an async function as well if i want to rebind them. And I need an async function to read the JSON data from backend. So my NewTaskTemplateSelector implements the FrontendApplicationContribution so that it can read ths JSON data in its initialize() function.

My question is, the console.log in the initialize() can print the data correctly but the this.templates in the selectTemplate() is still undefined. I don’t know how to deal with that.

Any help? Really appreciate.

Hi @inlann,

You’ll have to go one further back and rebind the TaskConfigurationManager, as well and override the getInitialConfigurationContent() method. But I since opening the quickinput is async anyway, I think it would be the right thing to make the TemplateSelector return a promise. Could you open an issue and maybe propose a PR?

Thanks for response!

Does that mean I need to write my own NewTaskConfigurationManager as well?

I’m wondering why the this.templates in function selectTemplates() is still undefined in the original post, even though I have assigned its value successfully in the initialize() function.

I tried to create my task template in frontend vie hard coding and it works:

export const makeTask: TaskTemplateEntry = {
    id: 'make',
    label: 'make',
    description: '',
    autoDetect: false,
    content: [
        '{',
        '\t"tasks": [',
        '\t\t{',
        '\t\t\t"label": "make",',
        '\t\t\t"command": "make",',
        '\t\t\t"type": "shell",',
        '\t\t\t"args": [',
        '\t\t\t\t// Add make args',
        '\t\t\t],',
        '\t\t}',
        '\t]',
        '}'
    ].join('\n')
};

@injectable()
export class NewTaskTemplateSelector {
    selectTemplates(): QuickPickValue<TaskTemplateEntry>[] {
        const templates: TaskTemplateEntry[] = [ makeTask ];
        return templates.map(t => ({
            label: t.label,
            description: t.description,
            value: t
        }));
    }
}

I’ll go with this solution for the time being but I still prefer to abstract the template as a configuration JSON file to reduce coupling rather than hard coding it. In that way, I can add a template by adding a new JSON file to the template directory.

I’ll create an issue if it’s necessary.