Open Cre8tiveDigital opened 3 years ago
Has anyone got any advice for me on this issue its been 20 days.
Thanks
Hi @Cre8tiveDigital
Sorry for the late reply and thanks for the compliments. Do you have an option to share with us your source code so we can reproduce/debug this issue?
Regards, Tomer
@Cre8tiveDigital in each of your sub-generators please add this code:
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.prompts = opts.prompts; // get a list of all parent prompts
this.parentPromptsQuantity = this.prompts.size(); // save the initial quantity of parent promts
// create all dynamic prompts (name and description only)
this.dynamicAddressPrompt = {name: "Dynamic Prompt Name", description: "Dynamic Prompt N Description"};
const prompts = [
{name: "First SubGen Prompt Name", description: "First SubGen Prompt Description"},
this.dynamicAddressPrompt,
{name: "Second SubGen Prompt Name", description: "Second SubGen Prompt Description"}];
// add sub-generator prompts to the parent generator prompts
this.prompts.splice(this.parentPromptsQuantity, 0, prompts);
}
Thank's Tomer, in my main application, I have the following,
const Generator = require("yeoman-generator");
const chalkPipe = require("chalk-pipe");
const Inquirer = require("inquirer");
const path = require("path");
const _ = require("lodash");
const types = require("@sap-devx/yeoman-ui-types");
const Datauri = require("datauri/sync");
const DEFAULT_IMAGE = require("./images/defaultImage");
module.exports = class extends Generator {
_getAnswer(name, res) {
return this._getOption(name) || _.get(res, "[${name}]");
}
_getOption(name) {
return _.get(this.options, "[${name}]");
}
_getImage(imagePath) {
let image;
try {
image = Datauri(imagePath).content;
} catch (error) {
image = DEFAULT_IMAGE;
this.log("Error = ${error}");
}
return image;
}
constructor(args, opts) {
super(args, opts);
this.data = opts.data;
this.appWizard = types.AppWizard.create(opts);
this.setPromptsCallback = fn => { // set callback method for yeoman-ui framework
if (this.prompts) {
this.prompts.setCallback(fn);
}
};
var prompts = [ // set list of all virtual prompts
{name: "Which Client", description: "Please choose a client you wish to create an email for."}
];
this.prompts = new types.Prompts(prompts); // save the propmpts in a variable
}
async prompting() {
let prompts = [
{
name: "client",
type: "list",
message: "Choose client",
guiOptions: {
type: "tiles"},
choices: [
{ value: "client1", name: "client1", description: "Select this to start building client 1 Emails", image: this._getImage(path.join(this.sourceRoot(), "../images/client1.png")) },
{ value: "client2", name: "client2", description: "Select this to start building client2 Emails", image: this._getImage(path.join(this.sourceRoot(), "../images/client2.png")) },
{ value: "client3", name: "client2", description: "Select this to start building client3 Emails", image: this._getImage(path.join(this.sourceRoot(), "../images/client3.jpg")) },
],
}
];
this.answers = await this.prompt(prompts);
this.answers.client = this._getAnswer("client", this.answers);
}
async writing() {
var _this = this;
if (this.answers.client === 'client1'){
this.composeWith(require.resolve("../client1"), { prompts: this.prompts, appWizard: this.appWizard });
}
else if (this.answers.client === 'client2'){
this.composeWith(require.resolve("../client2"), { prompts: this.prompts, appWizard: this.appWizard });
}
else if (this.answers.client === 'client3'){
this.composeWith(require.resolve("../client2"), { prompts: this.prompts, appWizard: this.appWizard });
}
};
}
And then this is the top of the client1 sub-generator
var Generator = require('yeoman-generator');
var _ = require('lodash');
var path = require('path');
var str;
const Datauri = require('datauri/sync');
const DEFAULT_IMAGE = require("./images/defaultImage");
const types = require('@sap-devx/yeoman-ui-types');
const fs = require('fs');
module.exports = class extends Generator {
constructor(args, opts) {
super(args, opts);
this.prompts = opts.prompts; // get list of all parent prompts
this.appWizard = opts.appWizard;
this.parentPromptsQuantity = this.prompts.size(); // save initial quantity of parent promts
// create all dynamic prompts (name and description only)
const prompts = [
{ name: "Multiple Versions", description: "Plese select if you require mutiple versions of this build, if so please then enter how many." },
{ name: "Job Number", description: "Please enter a job number" },
{ name: "Job Title", description: "Please enter the name of your project" }
];
// add sub-generator prompts to the parent generator prompts
this.prompts.splice(this.parentPromptsQuantity, 0, prompts);
}
_getAnswer(name, res) {
return this._getOption(name) || _.get(res, '[${name}]');
}
_getOption(name) {
return _.get(this.options, '[${name}]');
}
_requireLetters(value) {
if (/\s/.test(value)) {
// It has only spaces, or is empty
return 'Description must not contain spaces';
}
return true
}
async prompting() {
// Prompting the user if they require multiple version then how many
const prompts = [
{
type: "confirm",
name: "multipleversions",
message: "Do you require more than one version",
default: false
},
{
when: async response => {
return new Promise(resolve => {
setTimeout(() => {
resolve(this._getAnswer("multipleversions", response));
}, 2000);
});
},
type: "input",
name: "noofbuilds",
message: "How many versions do you require?"
}
];
this.answers = await this.prompt(prompts);
//Promting the user for a job number
const jobnumberPrompt = [
{
type: "input",
name: "jobnumber",
message: "Please enter a job number",
validate: function (answer) {
if (answer.length < 7) {
return 'Job number must be at least 7 numbers long';
}
return true;
},
},
];
const answersJobnumber = await this.prompt(jobnumberPrompt);
this.answers = Object.assign({}, this.answers, answersJobnumber);
//Promting the user for a description
const descriptionPrompt = [
{
type: "input",
name: "description",
message: "Please enter a name for your build",
validate: this._requireLetters
},
];
const answersDescription = await this.prompt(descriptionPrompt);
this.answers = Object.assign({}, this.answers, answersDescription);
}
_getImage(imagePath) {
let image;
try {
image = Datauri(imagePath).content;
} catch (error) {
image = DEFAULT_IMAGE;
this.log('Error = ${error}');
}
return image;
}
writing() {
To note after inserting client 3 the application crashes out as complete / not failed but it should be entering the client 3 sub-generator.
I could share the entire application with you but would need to do that on a private.
Thanks in advance.
Hi @Cre8tiveDigital
Thank you for bringing this scenario to us. We have investigate it and found that it's currently not supported. It's a valid and important flow and we intend to discuss it and give it priority.
As workaround we suggest to eliminate the use of the Prompts in the constructor.
Regards, Tomer
`
constructor(args, opts) {
super(args, opts);
this.data = opts.data;
this.appWizard = types.AppWizard.create(opts);
}
`
Thank's @tomer-epstein for the quick response, I implemented the suggested workaround which has fixed the issue on the main generator but once the sub-generator runs I get the finish button on each step instead of the next button. I have tried implementing the same workaround into the sub-generator but has no effect. I am still in development so can hope for an update if this has been made a priority.
Regards
Hi @Cre8tiveDigital ,
Did you eliminate the use of the Prompts in the constructor both for the root and sub generators? I suggest not call the composeWith in the 'writing' method, but in your case do it in the end of the prompt method.
Regards, Tomer
Thanks, @tomer-epstein,
This is a great workaround and seems to be working, I will implement it across all my subgens now and will update if I run into any more issues.
Thanks for the help
Hi, I am building a yeoman generator in a way that suits the UI running in VS (Great tool by the way), I have a master app which has one prompt in it which askes what client (sub-generator) you whish to choose. Once the user chooses a client (sub-generator) that client (sub-generator) is launched.
I have followed the example in the food q generator and when I only have one option in the master app I can use the
async initializing()
function but when I have more than one client (sub-generator) I have to move toasync writing()
function, which I am ok with as it seems to work fine and renders in Application Wizard ok apart from the next button on each prompt now appears to be a finish button.I can navigate through the whole process for UI purposes I would like this to be the Next button. Any help on this would be appreciated.
Also, I am looking for help with being able to stop the Application/generator if it detects there is already a project with the same name.
Thanks.