Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enquirer multi-step prompts #34

Closed
MatissJanis opened this issue Jun 2, 2020 · 12 comments · Fixed by #36 or #35
Closed

Enquirer multi-step prompts #34

MatissJanis opened this issue Jun 2, 2020 · 12 comments · Fixed by #36 or #35
Labels

Comments

@MatissJanis
Copy link

Awesome work on bringing old listr back to life!

One small nuance that is pretty annoying though: currently listr2 does not have support for multi-step enquirer prompts. It would be amazing, if this feature could be added.

{
  title: "Configure",
  task: async (ctx, task) => {
    ctx.input = await task.prompt([
      {
        type: 'input',
        name: 'name',
        message: 'What is your name?'
      },
      {
        type: 'input',
        name: 'username',
        message: 'What is your username?'
      }
    ]);
  },
}
@cenk1cenk2
Copy link
Collaborator

I will have a look. It should be related to the problems with the types. Default types of enquirer was not working correctly for me so i kind of rewrite the parts i required which are not correct at all.

@cenk1cenk2 cenk1cenk2 added the bug Something isn't working label Jun 2, 2020
@cenk1cenk2
Copy link
Collaborator

It seems I can make this work somehow with making both of the task.prompt thingies an array but it will lose the autocomplete functionality. This task.prompt is a jumper function that calls whatever you select in the first argument without using the type in enquirer. I do not know why but the type was causing problems for me which I forgot already, so I made it this way.

ctx.input = await task.prompt<boolean>([ 'Select', 'Select' ], [ { message: 'Do you love me?', choices: [ 'test', 'test', 'test', 'test' ] }, { message: 'Do you love me?', choices: [ 'test', 'test', 'test', 'test' ] } ])

The thing that this way will not be reliable enough for type-checking at least out of my league to implement. But you can achieve the same thing as follows if you even want an array as an end result as does the original enquirer multiple prompts do.

    ctx.input.push(await task.prompt('input', {
        type: 'input',
        name: 'name',
        message: 'What is your name?'
      })
    ctx.input.push(await task.prompt('input', {
        type: 'input',
        name: 'username',
        message: 'What is your username?'
      })

If this is sufficient enough, please close out the issue. Elsewise it may need more brainstorming or changing it at the core. In the meantime I will try to remember why type was causing problems for me.

@cenk1cenk2 cenk1cenk2 added enhancement New feature or request and removed bug Something isn't working labels Jun 2, 2020
@MatissJanis
Copy link
Author

Thanks for the super-quick response!

The above solution does indeed work for simple multi-step flows, but not for more advanced cases. For example, if using skip of enquirer.

Is there any particular reason that enquirer interface was changed? It would be very nice it we could use enquirer directly, without a gateway in this package.

@cenk1cenk2
Copy link
Collaborator

Since process.stdout is controlled by the package log-update for the default renderer, all packages that uses the stdout stream has to get passed through internally as data or it will mangle the log-update output. The problem that I encountered which I still fail to remember is while using enquirers exported types directly there were some mistakes in the types so I had adjusted them a little as a band-aid fix. While doing that if I used the type option in enquirer I had failed to get the autocomplete features of Typescript not reliable enough, this was a failure of myself. So I exported the type option in to its own variable and made a big switch that returns the prompt class directly. I should have an another go at this.

cenk1cenk2 added a commit that referenced this issue Jun 2, 2020
cenk1cenk2 added a commit that referenced this issue Jun 2, 2020
cenk1cenk2 pushed a commit that referenced this issue Jun 2, 2020
# [2.1.0-beta.2](v2.1.0-beta.1...v2.1.0-beta.2) (2020-06-02)

### Features

* **prompt:** make prompt module optional, be more compatible to underlying enqurier ([64cecc1](64cecc1)), closes [#34](#34)
* **prompt:** use enquirer directly ([b34e9d0](b34e9d0)), closes [#34](#34)
@cenk1cenk2
Copy link
Collaborator

🎉 This issue has been resolved in version 2.1.0-beta.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

cenk1cenk2 added a commit that referenced this issue Jun 2, 2020
This was linked to pull requests Jun 2, 2020
@cenk1cenk2
Copy link
Collaborator

Please check out the beta channel, installable by listr2@beta, this required some internal changes and due to it the way of requesting input from the user has changed a little.

Enquirer is now an optional dependency as well because I wanted to do that for quite some time. You should also explicitly install Enquirer to make this work.

I am looking forward to your feedback.

@MatissJanis
Copy link
Author

Hey!

Just tested the beta channel. Enquirer arrays now work, which is very nice. However, there's some functionality that we have lost.

Given this prompt definition, the skip step will receive answers = "A" (a string) rather than an object as described in Enquirer docs.

[{
    type: "select",
    name: "firstInput",
    message: "Please select something",
    choices: ["A", "B", "C"],
},
{
    type: "input",
    name: "secondInput",
    message: "Please type something in:",
    skip: function (answers) {
      return answers.firstInput === "A";
    }
}]

Additionally, if validate step is provided, the listr prompt seems to hang-up.

@cenk1cenk2
Copy link
Collaborator

cenk1cenk2 commented Jun 3, 2020

Validate seems to work for me like the one below. But skip does not pass in the results before it for me as well. But enquirer does not pass in the variable for skip I am not sure to have to check enquirer first.

      task: async (ctx, task): Promise<Record<string, boolean>> => ctx.input = await task.prompt<{ test: boolean, other: boolean }>([
        {
          type: 'Select',
          name: 'first',
          message: 'Please select something',
          choices: [ 'A', 'B', 'C' ],
          validate: (response): boolean | string => {
            //  i do declare you valid!
            if (response === 'A') {
              return true
            }
          }
        },
        {
          type: 'Input',
          name: 'second',
          message: 'Please type something in:',
          skip: (answers: { first: string }): boolean => {
            console.log(answers)
            return answers.first === 'A'
          }
        }
      ])

image
The result is not expected.

This seems the same with the enquirer as well.

  await Enquirer.prompt([
    {
      type: 'select',
      name: 'first',
      message: 'Please select something',
      choices: [ 'A', 'B', 'C' ],
      validate: (response): boolean | string => {
        //  i do declare you valid!
        if (response === 'A') {
          return true
        }
      }
    },
    {
      type: 'input',
      name: 'second',
      message: 'Please type something in:',
      skip: (answers: { first: string }): boolean => {
        console.log(answers)
        return answers.first === 'A'
      }
    }
  ])

@cenk1cenk2 cenk1cenk2 reopened this Jun 3, 2020
@cenk1cenk2
Copy link
Collaborator

This might be a problem with enquirer itself. I think you can get along with it separating multiple prompts to multiple listr tasks. It might not be the perfect code below but something along those lines.

task = new Listr<Ctx>([
  {
    title: 'This task will get your input.',
    task: async (ctx, task): Promise<Record<string, boolean>> => ctx.input = await task.prompt<{ test: boolean, other: boolean }>({
        type: 'Select',
        name: 'first',
        message: 'Please select something',
        choices: [ 'A', 'B', 'C' ],
        validate: (response): boolean | string => {
          //  i do declare you valid!
          if (response === 'A') {
            return true
          }
        }
      })
  },
  {
    title: 'Now I will show the input value.',
    skip: () => ctx.input === false
    task: async (ctx, task): void => ctx.input = await task.prompt<{ test: boolean, other: boolean }>({
      type: 'Select',
      name: 'first',
      message: 'Please select something',
      choices: [ 'A', 'B', 'C' ],
      validate: (response): boolean | string => {
        //  i do declare you valid!
        if (response === 'A') {
          return true
        }
      }
    }),
    options: {
      persistentOutput: true
    }
  }
], { concurrent: false })

@MatissJanis
Copy link
Author

Hey,

Yeah, currently I've separated the prompt tasks in individual listr steps. It's not ideal.. but works for now.

Judging from Enquirer type definitions, the skip method should have received an object. It's interesting that it doesn't.

@cenk1cenk2
Copy link
Collaborator

I might open a pull request to enquirer in upcoming days. I will close this issue again for now.

cenk1cenk2 pushed a commit that referenced this issue Jun 3, 2020
# [2.1.0](v2.0.4...v2.1.0) (2020-06-03)

### Bug Fixes

* **deps:** remove trivial deps ([de8dec0](de8dec0))
* **deps:** remove unnecassary types ([b37f416](b37f416))
* **deps:** updated deps to latest ([c4ad38f](c4ad38f))
* **figures:** made microsoft icons to use the fancy ones, even though it may fail in some cases ([f0e5817](f0e5817)), closes [#31](#31)
* **prompt:** enquirer to peer ([cae55e9](cae55e9))
* **prompt:** types ([110130a](110130a))
* **prompts:** fixed type for array prompts, added name as mandatory ([a08b1e4](a08b1e4))
* **stream:** fixed streams added example ([614d89f](614d89f)), closes [#37](#37)

### Features

* **prompt:** make prompt module optional, be more compatible to underlying enqurier ([64cecc1](64cecc1)), closes [#34](#34)
* **prompt:** use enquirer directly ([b34e9d0](b34e9d0)), closes [#34](#34)
* **renderer:** added hook and stdout support ([bd73c68](bd73c68)), closes [#31](#31)
@cenk1cenk2
Copy link
Collaborator

🎉 This issue has been resolved in version 2.1.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants