Turning this into a separate issue, to make tracking a bit easier - it's based on this: https://virtualmin.com/node/22867#comment-126823
Agreed, a custom wizard framework would be a good idea. Oddly I haven't used wizards much in Webmin/Virtualmin previously, which is likely why this hasn't been done before.
As mentioned here, it seems that the existing "custom commands" feature in webmin would provide for a solid foundation to design a dynamic wizard framework on top of it - where a wizard would be an array of wizard pages, and each page could contain fields (analogous to the ones used by custom commands) or custom commands directly.
Supporting this, would make it possible for people to easily create wizards using custom commands. Based on playing with the code, it seems there's very little missing to make this happen actually.
So here's a random collection of thoughts on integrating wizards and custom commands:
- being able to package wizards/custom commands analogous to wbt packaging would be useful to easily exchange them, i.e. web-based downloading/installation
- some additional field types would be useful, especially pre-populated lists - for things like local vhosts, configured cluster servers etc
- currently, the target server must be specified when editing the command, it may be useful to provide an option to select this at runtime, i.e. provide a new field type "webmin servers" and an option where the server can be selected when running the command
- the notion of having prerequisites (analogous to webmin modules) should probably also be supported by custom commands, i.e. to check if certain packages are installed - sort of like "precondition"
- a wizard will typically involve multiple pages, but also multiple stages, where commands may need to be running in the background, i.e. scheduled via cron for example
- it would be very useful to directly expose the webmin/virtualmin CLI tools to the custom commands feature
Ideally, the UI part would be kept separate, so that wizards could also be run via the CLI, i.e. using GNU readline() then.