diff --git a/backend/.nycrc.json b/backend/.nycrc.json index b880d85f7..1f409a20c 100644 --- a/backend/.nycrc.json +++ b/backend/.nycrc.json @@ -8,7 +8,7 @@ "temp-dir": "./reports/.nyc_output", "report-dir": "./reports/coverage", "check-coverage": true, - "branches": 81, + "branches": 82, "lines": 88, "functions": 85, "statements": 88 diff --git a/backend/package.json b/backend/package.json index a7971e87e..802bef8fb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "yeoman-ui", - "version": "1.1.1", + "version": "1.1.2", "displayName": "Application Wizard", "publisher": "SAPOS", "author": { @@ -53,7 +53,7 @@ }, { "command": "exploreGenerators", - "title": "Explore Generators" + "title": "Explore and Install Generators" } ], "menus": { diff --git a/backend/src/exploregens.ts b/backend/src/exploregens.ts index e91fc8d0f..57cee98b0 100644 --- a/backend/src/exploregens.ts +++ b/backend/src/exploregens.ts @@ -13,7 +13,7 @@ export class ExploreGens { public static getInstallationLocation(wsConfig: any) { return _.trim(wsConfig.get(ExploreGens.INSTALLATION_LOCATION)); } - + private static readonly INSTALLATION_LOCATION = "Explore Generators.installationLocation"; private logger: IChildLogger; @@ -22,7 +22,9 @@ export class ExploreGens { private cachedInstalledGeneratorsPromise: Promise; private context: any; private vscode: any; + private isInTheiaCached: boolean; + private readonly theiaCommands: string[] = ["theia.open", "preferences:open", "keymaps:open", "workspace:openRecent"]; private readonly LAST_AUTO_UPDATE_DATE = "Explore Generators.lastAutoUpdateDate"; private readonly SEARCH_QUERY = "Explore Generators.searchQuery"; private readonly AUTO_UPDATE = "Explore Generators.autoUpdate" @@ -80,6 +82,7 @@ export class ExploreGens { this.rpc.registerMethod({ func: this.uninstall, thisArg: this }); this.rpc.registerMethod({ func: this.isInstalled, thisArg: this }); this.rpc.registerMethod({ func: this.getRecommendedQuery, thisArg: this }); + this.rpc.registerMethod({ func: this.isInTheia, thisArg: this }); } private async updateAllInstalledGenerators() { @@ -245,7 +248,7 @@ export class ExploreGens { if (_.isEmpty(customLocation)) { return env.getNpmPaths(); } - + return [path.join(customLocation, this.NODE_MODULES)]; } @@ -257,5 +260,15 @@ export class ExploreGens { return packagePath.substring(nodeModulesIndex + this.NODE_MODULES.length + 1); }) resolve(_.uniq(gensFullNames)); - } + } + + private async isInTheia() { + if (_.isNil(this.isInTheiaCached)) { + const commands = await this.vscode.commands.getCommands(true); + const foundCommands = _.intersection(commands, this.theiaCommands); + this.isInTheiaCached = !_.isEmpty(foundCommands); + } + + return this.isInTheiaCached; + } } diff --git a/backend/src/panels/AbstractWebviewPanel.ts b/backend/src/panels/AbstractWebviewPanel.ts index 3fd49aed5..a58b15564 100644 --- a/backend/src/panels/AbstractWebviewPanel.ts +++ b/backend/src/panels/AbstractWebviewPanel.ts @@ -25,13 +25,9 @@ export abstract class AbstractWebviewPanel { protected readonly defaultNpmPaths: string[] = Environment.createEnv().getNpmPaths(); public loadWebviewPanel(uiOptions?: any) { - if (this.webViewPanel && _.isEmpty(uiOptions)) { - this.webViewPanel.reveal(); - } else { - this.disposeWebviewPanel(); - const webViewPanel = this.createWebviewPanel(); - this.setWebviewPanel(webViewPanel, uiOptions); - } + this.disposeWebviewPanel(); + const webViewPanel = this.createWebviewPanel(); + this.setWebviewPanel(webViewPanel, uiOptions); } protected constructor(context: vscode.ExtensionContext) { diff --git a/backend/src/panels/ExploreGensPanel.ts b/backend/src/panels/ExploreGensPanel.ts index a9aeef850..03ceee127 100644 --- a/backend/src/panels/ExploreGensPanel.ts +++ b/backend/src/panels/ExploreGensPanel.ts @@ -17,13 +17,21 @@ export class ExploreGensPanel extends AbstractWebviewPanel { public constructor(context: vscode.ExtensionContext) { super(context); this.viewType = "exploreGens"; - this.viewTitle = "Explore Generators"; + this.viewTitle = "Explore and Install Generators"; this.focusedKey = "exploreGens.Focused"; this.htmlFileName = path.join("exploregens", "index.html"); } + public loadWebviewPanel() { + if (this.webViewPanel) { + this.webViewPanel.reveal(); + } else { + super.loadWebviewPanel(); + } + } + public disposeWebviewPanel() { super.disposeWebviewPanel(); this.exploreGens = null; - } + } } diff --git a/backend/src/panels/YeomanUIPanel.ts b/backend/src/panels/YeomanUIPanel.ts index 43765fa7a..3b1f319da 100644 --- a/backend/src/panels/YeomanUIPanel.ts +++ b/backend/src/panels/YeomanUIPanel.ts @@ -35,7 +35,7 @@ export class YeomanUIPanel extends AbstractWebviewPanel { vscodeYouiEvents, this.outputChannel, this.logger, - { genFilter: this.genFilter, messages: this.messages, defaultNpmPaths: this.getDefaultPaths() }, + { genFilter: this.genFilter, messages: this.messages, data: _.get(uiOptions, "data"), defaultNpmPaths: this.getDefaultPaths() }, _.get(vscode, "workspace.workspaceFolders[0].uri.fsPath")); this.yeomanui.registerCustomQuestionEventHandler("file-browser", "getFilePath", this.showOpenFileDialog.bind(this)); this.yeomanui.registerCustomQuestionEventHandler("folder-browser", "getPath", this.showOpenFolderDialog.bind(this)); diff --git a/backend/tests/exploregens.spec.ts b/backend/tests/exploregens.spec.ts index de133a49c..63c618f07 100644 --- a/backend/tests/exploregens.spec.ts +++ b/backend/tests/exploregens.spec.ts @@ -47,7 +47,8 @@ const testVscode = { globalState }, commands: { - executeCommand: () => true + executeCommand: () => Promise.reject("not implemented"), + getCommands: () => Promise.reject("not implemented") } }; @@ -150,18 +151,43 @@ describe('exploregens unit test', () => { vscodeCommandsMock.verify(); }); + describe("isInTheia", () => { + it("use cached value", async () => { + exploregens["isInTheiaCached"] = true; + vscodeCommandsMock.expects("getCommands").never(); + const res = await exploregens["isInTheia"](); + expect(res).to.be.true; + }); + + it("returns true", async () => { + exploregens["isInTheiaCached"] = undefined; + vscodeCommandsMock.expects("getCommands").withExactArgs(true).resolves(["theia.open", "preferences:open"]); + const res = await exploregens["isInTheia"](); + expect(res).to.be.true; + }); + + it("returns false", async () => { + exploregens["isInTheiaCached"] = undefined; + vscodeCommandsMock.expects("getCommands").withExactArgs(true).resolves(["workbench.action.openGlobalKeybindings"]); + const res = await exploregens["isInTheia"](); + expect(res).to.be.false; + }); + }); + describe("NPM", () => { it("win32 platform", () => { const stub = sinon.stub(process, 'platform').value("win32"); const exploregens1 = new ExploreGens(rpc, null, testVscode.context, testVscode); - expect(exploregens1["NPM"]).to.be.equal("npm.cmd"); + const res = exploregens1["NPM"]; + expect(res).to.be.equal("npm.cmd"); stub.restore(); }); it("linux platfrom", () => { const stub = sinon.stub(process, 'platform').value("linux"); const exploregens2 = new ExploreGens(rpc, null, testVscode.context, testVscode); - expect(exploregens2["NPM"]).to.be.equal("npm"); + const res = exploregens2["NPM"]; + expect(res).to.be.equal("npm"); stub.restore(); }); }); @@ -172,6 +198,7 @@ describe('exploregens unit test', () => { rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["install"], thisArg: exploregens }); rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["uninstall"], thisArg: exploregens }); rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["isInstalled"], thisArg: exploregens }); + rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["isInTheia"], thisArg: exploregens }); rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["getRecommendedQuery"], thisArg: exploregens }); const customLocation = path.join("home", "user", "projects"); @@ -186,6 +213,7 @@ describe('exploregens unit test', () => { rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["install"], thisArg: exploregens }); rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["uninstall"], thisArg: exploregens }); rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["isInstalled"], thisArg: exploregens }); + rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["isInTheia"], thisArg: exploregens }); rpcMock.expects("registerMethod").withExactArgs({ func: exploregens["getRecommendedQuery"], thisArg: exploregens }); workspaceConfigMock.expects("get").withExactArgs(ExploreGens["INSTALLATION_LOCATION"]).returns(""); diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 2b00acf4f..83895b1c5 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -6,10 +6,10 @@ :height="64" :width="64" :color="isLoadingColor" - background-color="transparent" + background-color="transparent" loader="spinner" > - +
- + @@ -49,21 +54,21 @@ /> - -
-
-
-
+ +
+
- + mdi-chevron-leftBack - Nextmdi-chevron-right + Next + mdi-chevron-right
@@ -149,7 +154,9 @@ export default { ); }, headerTitle() { - const titleSuffix = _.isEmpty(this.generatorPrettyName) ? "" : ` - ${this.generatorPrettyName}`; + const titleSuffix = _.isEmpty(this.generatorPrettyName) + ? "" + : ` - ${this.generatorPrettyName}`; return `${this.messages.yeoman_ui_title}${titleSuffix}`; }, currentPrompt() { @@ -158,8 +165,10 @@ export default { isNoGenerators() { const promptName = _.get(this.currentPrompt, "name"); const message = _.get(this.messages, "select_generator_name", ""); - const noChoices = _.isEmpty(_.get(this.currentPrompt, "questions[0].choices")); - return (promptName === message) && noChoices; + const noChoices = _.isEmpty( + _.get(this.currentPrompt, "questions[0].choices") + ); + return promptName === message && noChoices; } }, watch: { @@ -183,14 +192,16 @@ export default { setBusyIndicator() { this.showBusyIndicator = _.isEmpty(this.prompts) || - (this.currentPrompt - && (this.currentPrompt.status === PENDING || this.currentPrompt.status === EVALUATING) - && !this.isDone); + (this.currentPrompt && + (this.currentPrompt.status === PENDING || + this.currentPrompt.status === EVALUATING) && + !this.isDone); }, back() { - this.gotoStep(1); // go 1 step back + this.gotoStep(1); // go 1 step back }, - gotoStep(numOfSteps) { // go numOfSteps step back + gotoStep(numOfSteps) { + // go numOfSteps step back try { this.isReplaying = true; this.numOfSteps = numOfSteps; @@ -275,20 +286,21 @@ export default { if (question[prop] === FUNCTION) { const that = this; question[prop] = async (...args) => { - if (this.currentPrompt) { - this.currentPrompt.status = EVALUATING; - } + if (this.currentPrompt) { + this.currentPrompt.status = EVALUATING; + } - try { - return await that.rpc.invoke("evaluateMethod", [ - args, - question.name, - prop - ]); - } catch(e) { - that.showBusyIndicator = false; - throw(e); - }}; + try { + return await that.rpc.invoke("evaluateMethod", [ + args, + question.name, + prop + ]); + } catch (e) { + that.showBusyIndicator = false; + throw e; + } + }; } } } @@ -321,7 +333,10 @@ export default { promptDescription = this.messages.select_generator_description; promptName = this.messages.select_generator_name; } else { - const promptToDisplay = _.get(this.promptsInfoToDisplay, "[" + (this.promptIndex - 1) +"]"); + const promptToDisplay = _.get( + this.promptsInfoToDisplay, + "[" + (this.promptIndex - 1) + "]" + ); promptDescription = _.get(promptToDisplay, "description", ""); promptName = _.get(promptToDisplay, "name", name); } @@ -365,8 +380,8 @@ export default { if (!window.vscode) { // eslint-disable-next-line window.vscode = acquireVsCodeApi(); - } - + } + return window.vscode; } }, @@ -400,13 +415,12 @@ export default { }); }); - this.displayGeneratorsPrompt(); + this.displayGeneratorsPrompt(); }, async setMessagesAndSaveState() { const uiOptions = await this.rpc.invoke("getState"); this.messages = uiOptions.messages; - const genFilter = uiOptions.genFilter; - this.isGeneric = _.isEmpty(_.get(genFilter, "types")) && _.isEmpty(_.get(genFilter, "categories")); + this.isGeneric = _.get(this.messages, "panel_title") === "Yeoman UI"; const vscodeApi = this.getVsCodeApi(); if (vscodeApi) { vscodeApi.setState(uiOptions); @@ -443,7 +457,7 @@ export default { dataObj.rpc = this.rpc; Object.assign(this.$data, dataObj); this.init(); - + this.displayGeneratorsPrompt(); } }, @@ -497,7 +511,12 @@ div.consoleClassVisible .v-footer { } .diagonal { width: 80px; - background: linear-gradient(120deg, var(--vscode-editor-background, #1e1e1e) 0%, var(--vscode-editor-background, #1e1e1e) 50%, transparent 50%); + background: linear-gradient( + 120deg, + var(--vscode-editor-background, #1e1e1e) 0%, + var(--vscode-editor-background, #1e1e1e) 50%, + transparent 50% + ); background-color: var(--vscode-editorWidget-background, #252526); } .bottom-right-col { @@ -510,6 +529,6 @@ div.consoleClassVisible .v-footer { padding-right: 25px; } .bottom-buttons-col > .v-btn:not(:last-child) { - margin-right: 10px !important; + margin-right: 10px !important; } diff --git a/frontend/src/ExploreGensApp.vue b/frontend/src/ExploreGensApp.vue index 2160f9663..ebf50274d 100644 --- a/frontend/src/ExploreGensApp.vue +++ b/frontend/src/ExploreGensApp.vue @@ -1,12 +1,12 @@