Hey
First of all: Great Extension, really proving quite useful for my team. Backgroud: we have some workflows in which edits in the wiki trigger scripts on the host. I'm showing the current state of these scripts to my team via this extensions. Unfortunately, these people find it sometimes difficult to navigate the SpecialPage because all this "techy stuff in the toc" (to paraphrase the feedback).
I'm suggesting a change in handling of `$wgHostStatsCommands` to allow for the entries to either be a string (and render the command output like it is rendered currently) or an array in the form of
```
[
'title' => 'title of the section',
'command' => 'command as before',
'arguments' => 'command line arguments',
'description' => 'an optional description text'
],
```
Code to accomplish this (including removal of some deprecations) could look like this:
```
<?php
use MediaWiki\MediaWikiServices;
use MediaWiki\Shell\Shell;
/**
* The file that implements Special:HostStats.
*
* @file
* @ingroup Extensions
*/
class SpecialHostStats extends SpecialPage {
public function __construct() {
parent::__construct( 'HostStats' );
}
/**
* @param string|null $par
*/
public function execute( $par ) {
global $wgHostStatsCommands;
if ( !MediaWikiServices::getInstance()->getPermissionManager()->userHasRight( $this->getUser(), 'hoststats' ) ) {
throw new PermissionsError( 'hoststats' );
}
if ( Shell::isDisabled() ) {
throw new \MediaWiki\ShellDisabledError();
}
$this->setHeaders();
$this->getOutput()->setPageTitle( wfMessage( 'hoststats-title' )->escaped() );
$outpage = wfMessage( 'hoststats-intro' )->escaped();
$outpage .= "\n";
foreach ( $wgHostStatsCommands as $entryif ( Shell::isDisabled() ) {
list( $title, $description,$outpage .= '<p />' . $command ) = $this->processEntry( $entry );wfMessage( 'hoststats-shell-disabled-error' )->parse();
$outpage .= '<h3>' . $title . '</h3>'; } else {
if ( $description ) {foreach ($wgHostStatsCommands as $entry) {
list($title, $description, $command) = $this->processEntry($entry);
$outpage .= '<h3>' . $title . '</h3>';
if ($description) {
$outpage .= "\n<p />\n" . $description;
}
$outpage .= "\n<pre>\n" . $this->query($command) . "</pre>";
$outpage .= "\n<pre>\n" . $this->query( $command ) . "</pre>";}
}
$this->getOutput()->addWikiTextAsInterface( $outpage );
}
/**
* @inheritDoc
*/
protected function query( $query ) {
$result = Shell::command( $query[] )
->restrict( Shell::RESTRICT_DEFAULT | Shell::NO_NETWORK->unsafeParams( (array)$query )
->includeStderr( true )
->restrict( Shell::RESTRICT_DEFAULT )
->execute();
return $result->getStdout();
}
/**
* @return string
*/
protected function getGroupName() {
return 'wiki';
}
/**
* @param string|string[] $entry
* @return string[]
*/
private function processEntry( $entry ): array {
if ( is_string( $entry ) ) {
return [ $entry, null, $entry ];
#return [ $entry, null, explode( ' ', $entry ) ];
}
$cmd = $entry['command'] ?? ( $entry[2] ?? 'undefined' );
if ( !empty( $entry['args'] ) || !empty( $entry['arguments'] ) ) {
$cmd = [ $cmd, $entry['args'] ?? $entry['arguments'] ];
}
return [
$entry['title'] ?? ( $entry[1] ?? ( $entry['command'] ?? ( $entry[2] ?? 'undefined' ) ) ),
$entry['description'] ?? ( $entry[1] ?? null ),
$cmd,
];
}
}
```