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

Adds Reversible Forms to Prompts #118

Merged
merged 10 commits into from
Apr 15, 2024
Merged

Conversation

lukeraymonddowning
Copy link
Contributor

@lukeraymonddowning lukeraymonddowning commented Feb 26, 2024

Hey all!

This PR adds support for revertable forms to Prompts. Here's a little demo video,
which you can play with for yourself using php playground/form.php on this branch.

Screen.Recording.2024-04-10.at.10.28.22-1.mov

Purpose

Often, when navigating through a lenthy series of prompts, I make typos or mistakes
and need to go back to make edits. Currently, the only way to fix them is to cancel
the command and start again from scratch.

To fix that frustration, you may now declare a series of steps that the user will
be taken through. By using the CTRL+U key combo, any step in the process can be
reverted by the user to retry the previous step again.

Usage

A series of steps can be created using the form function,
followed by the relevant prompt method for each desired step, like so:

$responses = form()
    ->text('What is your name?')
    ->select('What is your favourite language?', ['PHP', 'JS'])
    ->submit();

Calling submit executes the steps in the terminal. In this case, once the user reaches
the "What is your favourite language?" prompt, they can hit CTRL+U (alternatively CMD+BACKSPACE on Mac)
to go back to "What is your name?" and fill it out again.

All prompts that support the $default parameter will autofill with the previously entered value when reverting to them, making it easy to fix little typos without having to type everything out again.

Utilising previous responses

The submit method will return all responses at the end of the run. However, you may
need access to previous step responses inside of a later step. Each step is passed
an array of all previous responses:

$responses = form()
    ->text('What is your name?')
    ->select('What is your favourite language?', ['PHP', 'JS'])
    ->add(fn ($responses) => note("Your name is {$responses[0]} and your language is {$responses[1]}"))
    ->submit();

Often, finding the response by index is not a nice experience and can be too brittle. To remedy this, you can provide a name for each step, which will be used as the index in the response array:

$responses = form()
    ->text('What is your name?', name: 'name')
    ->add(fn () => select('What is your favourite language?', ['PHP', 'JS']), name: 'language')
    ->add(fn ($responses) => note("Your name is {$responses['name']} and your language is {$responses['language']}"))
    ->submit();

Wrap-up

All in all, I really think this will make life easier and less frustrating for complex prompt sequences. I'm
excited to hear your thoughts!

Thank you for all the hard work maintaining and working on Prompts; it's very much appreciated.

Regards,
Luke

@taylorotwell
Copy link
Member

Converting to draft so @jessarcher can have a look.

@jessarcher
Copy link
Member

jessarcher commented Feb 27, 2024

Hey @lukeraymonddowning,

This looks really cool! A few questions:

  1. I wonder whether we could expose methods for each prompt directly on the step builder to avoid having to do the closure dance. For example:

    $responses = steps()
        ->text('What is your name?')
        ->select('What is your favourite language?', ['PHP', 'JS'])
        ->run();

    This could potentially be achieved with a magic __call method that checks for a namespaced function with the passed name, although we'd lose IDE help on the available methods and parameters.

    If we think IDE support is important (and I tend to think it is), we could add @method docblocks for each prompt, or we could just add real methods and not do the __call method. Either way, it adds a small maintenance burden as the step builder must be kept in sync with any changes or additions, but I think it's worth it for a better developer experience (and prompts don't change often anyway).

    Parameters like key could even be exposed on these methods, so you wouldn't need to pass a closure to set them. I then think the only reason to pass a closure is to receive the previous responses.

  2. Regarding the revert behaviour, I'm a bit hesitant about the complexity this feature might introduce. It's also potentially a bit confusing about which prompt should have revert: false. In the UI it feels like it's the current prompt that can't be reverted, while in reality it's the previous prompt that defined it. In my mind, the steps are almost like creating a form on the web where no actions are taken until the entire form is completed. What do you think? Is revert crucial for your use cases?

  3. Related to the above form analogy, I wondered whether the function could be named form instead of steps to continue the parallel between methods like select and <select>. The run method could even be named submit, although that might imply an actual button to confirm things (which, if it existed, would give users a chance to undo the final prompt). The key parameter could become name, again to continue the analogy. What do you think?

@lukeraymonddowning
Copy link
Contributor Author

Hey @jessarcher! Thanks for the feedback. All changes implemented and ready for review.

@lukeraymonddowning lukeraymonddowning changed the title Adds Reversible Steps to Prompts Adds Reversible Forms to Prompts Apr 10, 2024
Copy link
Member

@jessarcher jessarcher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works great!

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

Successfully merging this pull request may close these issues.

3 participants