Merge branch 'feature/more-intuitive-module-installation-8191'

resolves #8191
This commit is contained in:
Johannes Meyer 2015-01-22 13:34:51 +01:00
commit 13c2a3a967
15 changed files with 434 additions and 354 deletions

View File

@ -512,7 +512,7 @@ class Form extends Zend_Form
$el = parent::createElement($type, $name, $options); $el = parent::createElement($type, $name, $options);
if (($description = $el->getDescription()) !== null && ($label = $el->getDecorator('label')) !== null) { if (($description = $el->getDescription()) !== null && ($label = $el->getDecorator('label')) !== false) {
$label->setOptions(array( $label->setOptions(array(
'title' => $description, 'title' => $description,
'class' => 'has-feedback' 'class' => 'has-feedback'

View File

@ -39,6 +39,13 @@ class Wizard
*/ */
const BTN_PREV = 'btn_prev'; const BTN_PREV = 'btn_prev';
/**
* This wizard's parent
*
* @var Wizard
*/
protected $parent;
/** /**
* The name of the wizard's current page * The name of the wizard's current page
* *
@ -71,19 +78,55 @@ class Wizard
} }
/**
* Return this wizard's parent or null in case it has none
*
* @return Wizard|null
*/
public function getParent()
{
return $this->parent;
}
/**
* Set this wizard's parent
*
* @param Wizard $wizard The parent wizard
*
* @return self
*/
public function setParent(Wizard $wizard)
{
$this->parent = $wizard;
return $this;
}
/** /**
* Return the pages being part of this wizard * Return the pages being part of this wizard
* *
* In case this is a nested wizard a flattened array of all contained pages is returned.
*
* @return array * @return array
*/ */
public function getPages() public function getPages()
{ {
return $this->pages; $pages = array();
foreach ($this->pages as $page) {
if ($page instanceof self) {
$pages = array_merge($pages, $page->getPages());
} else {
$pages[] = $page;
}
}
return $pages;
} }
/** /**
* Return the page with the given name * Return the page with the given name
* *
* Note that it's also possible to retrieve a nested wizard's page by using this method.
*
* @param string $name The name of the page to return * @param string $name The name of the page to return
* *
* @return null|Form The page or null in case there is no page with the given name * @return null|Form The page or null in case there is no page with the given name
@ -98,22 +141,31 @@ class Wizard
} }
/** /**
* Add a new page to this wizard * Add a new page or wizard to this wizard
* *
* @param Form $page The page to add to the wizard * @param Form|Wizard $page The page or wizard to add to the wizard
* *
* @return self * @return self
*/ */
public function addPage(Form $page) public function addPage($page)
{ {
if (! $page instanceof Form && ! $page instanceof self) {
throw InvalidArgumentException(
'The $page argument must be an instance of Icinga\Web\Form '
. 'or Icinga\Web\Wizard but is of type: ' . get_class($page)
);
} elseif ($page instanceof self) {
$page->setParent($this);
}
$this->pages[] = $page; $this->pages[] = $page;
return $this; return $this;
} }
/** /**
* Add multiple pages to this wizard * Add multiple pages or wizards to this wizard
* *
* @param array $pages The pages to add to the wizard * @param array $pages The pages or wizards to add to the wizard
* *
* @return self * @return self
*/ */
@ -148,6 +200,10 @@ class Wizard
*/ */
public function getCurrentPage() public function getCurrentPage()
{ {
if ($this->parent) {
return $this->parent->getCurrentPage();
}
if ($this->currentPage === null) { if ($this->currentPage === null) {
$this->assertHasPages(); $this->assertHasPages();
$pages = $this->getPages(); $pages = $this->getPages();
@ -202,6 +258,10 @@ class Wizard
{ {
$page = $this->getCurrentPage(); $page = $this->getCurrentPage();
if (($wizard = $this->findWizard($page)) !== null) {
return $wizard->handleRequest($request);
}
if ($request === null) { if ($request === null) {
$request = $page->getRequest(); $request = $page->getRequest();
} }
@ -238,6 +298,39 @@ class Wizard
return $request; return $request;
} }
/**
* Return the wizard for the given page or null if its not part of a wizard
*
* @param Form $page The page to return its wizard for
*
* @return Wizard|null
*/
protected function findWizard(Form $page)
{
foreach ($this->getWizards() as $wizard) {
if ($wizard->getPage($page->getName()) === $page) {
return $wizard;
}
}
}
/**
* Return this wizard's child wizards
*
* @return array
*/
protected function getWizards()
{
$wizards = array();
foreach ($this->pages as $pageOrWizard) {
if ($pageOrWizard instanceof self) {
$wizards[] = $pageOrWizard;
}
}
return $wizards;
}
/** /**
* Return the request data based on given form's request method * Return the request data based on given form's request method
* *
@ -264,6 +357,10 @@ class Wizard
*/ */
protected function getRequestedPage(array $requestData) protected function getRequestedPage(array $requestData)
{ {
if ($this->parent) {
return $this->parent->getRequestedPage($requestData);
}
if (isset($requestData[static::BTN_NEXT])) { if (isset($requestData[static::BTN_NEXT])) {
return $requestData[static::BTN_NEXT]; return $requestData[static::BTN_NEXT];
} elseif (isset($requestData[static::BTN_PREV])) { } elseif (isset($requestData[static::BTN_PREV])) {
@ -280,6 +377,10 @@ class Wizard
*/ */
protected function getDirection(Request $request = null) protected function getDirection(Request $request = null)
{ {
if ($this->parent) {
return $this->parent->getDirection($request);
}
$currentPage = $this->getCurrentPage(); $currentPage = $this->getCurrentPage();
if ($request === null) { if ($request === null) {
@ -299,7 +400,7 @@ class Wizard
/** /**
* Return the new page to set as current page * Return the new page to set as current page
* *
* Permission is checked by verifying that the requested page's previous page has page data available. * Permission is checked by verifying that the requested page or its previous page has page data available.
* The requested page is automatically permitted without any checks if the origin page is its previous * The requested page is automatically permitted without any checks if the origin page is its previous
* page or one that occurs later in order. * page or one that occurs later in order.
* *
@ -312,11 +413,15 @@ class Wizard
*/ */
protected function getNewPage($requestedPage, Form $originPage) protected function getNewPage($requestedPage, Form $originPage)
{ {
if ($this->parent) {
return $this->parent->getNewPage($requestedPage, $originPage);
}
if (($page = $this->getPage($requestedPage)) !== null) { if (($page = $this->getPage($requestedPage)) !== null) {
$permitted = true; $permitted = true;
$pages = $this->getPages(); $pages = $this->getPages();
if (($index = array_search($page, $pages, true)) > 0) { if (! $this->hasPageData($requestedPage) && ($index = array_search($page, $pages, true)) > 0) {
$previousPage = $pages[$index - 1]; $previousPage = $pages[$index - 1];
if ($originPage === null || ($previousPage->getName() !== $originPage->getName() if ($originPage === null || ($previousPage->getName() !== $originPage->getName()
&& array_search($originPage, $pages, true) < $index)) && array_search($originPage, $pages, true) < $index))
@ -335,6 +440,36 @@ class Wizard
); );
} }
/**
* Return the next or previous page based on the given one
*
* @param Form $page The page to skip
*
* @return Form
*/
protected function skipPage(Form $page)
{
if ($this->parent) {
return $this->parent->skipPage($page);
}
if ($this->hasPageData($page->getName())) {
$pageData = & $this->getPageData();
unset($pageData[$page->getName()]);
}
$pages = $this->getPages();
if ($this->getDirection() === static::FORWARD) {
$nextPage = $pages[array_search($page, $pages, true) + 1];
$newPage = $this->getNewPage($nextPage->getName(), $page);
} else { // $this->getDirection() === static::BACKWARD
$previousPage = $pages[array_search($page, $pages, true) - 1];
$newPage = $this->getNewPage($previousPage->getName(), $page);
}
return $newPage;
}
/** /**
* Return whether the given page is this wizard's last page * Return whether the given page is this wizard's last page
* *
@ -344,10 +479,27 @@ class Wizard
*/ */
protected function isLastPage(Form $page) protected function isLastPage(Form $page)
{ {
if ($this->parent) {
return $this->parent->isLastPage($page);
}
$pages = $this->getPages(); $pages = $this->getPages();
return $page->getName() === end($pages)->getName(); return $page->getName() === end($pages)->getName();
} }
/**
* Return whether all of this wizard's pages were visited by the user
*
* The base implementation just verifies that the very last page has page data available.
*
* @return bool
*/
public function isComplete()
{
$pages = $this->getPages();
return $this->hasPageData($pages[count($pages) - 1]->getName());
}
/** /**
* Set whether this wizard has been completed * Set whether this wizard has been completed
* *
@ -421,6 +573,10 @@ class Wizard
*/ */
public function getSession() public function getSession()
{ {
if ($this->parent) {
return $this->parent->getSession();
}
return Session::getSession()->getNamespace(get_class($this)); return Session::getSession()->getNamespace(get_class($this));
} }

View File

@ -4,15 +4,12 @@
namespace Icinga\Module\Monitoring; namespace Icinga\Module\Monitoring;
use Icinga\Application\Icinga;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Wizard; use Icinga\Web\Wizard;
use Icinga\Web\Request; use Icinga\Web\Request;
use Icinga\Module\Setup\Setup; use Icinga\Module\Setup\Setup;
use Icinga\Module\Setup\SetupWizard; use Icinga\Module\Setup\SetupWizard;
use Icinga\Module\Setup\Requirements; use Icinga\Module\Setup\Requirements;
use Icinga\Module\Setup\Utils\MakeDirStep;
use Icinga\Module\Setup\Utils\EnableModuleStep;
use Icinga\Module\Setup\Forms\SummaryPage; use Icinga\Module\Setup\Forms\SummaryPage;
use Icinga\Module\Monitoring\Forms\Setup\WelcomePage; use Icinga\Module\Monitoring\Forms\Setup\WelcomePage;
use Icinga\Module\Monitoring\Forms\Setup\BackendPage; use Icinga\Module\Monitoring\Forms\Setup\BackendPage;
@ -37,7 +34,7 @@ class MonitoringWizard extends Wizard implements SetupWizard
$this->addPage(new LivestatusResourcePage()); $this->addPage(new LivestatusResourcePage());
$this->addPage(new InstancePage()); $this->addPage(new InstancePage());
$this->addPage(new SecurityPage()); $this->addPage(new SecurityPage());
$this->addPage(new SummaryPage()); $this->addPage(new SummaryPage(array('name' => 'setup_monitoring_summary')));
} }
/** /**
@ -47,7 +44,7 @@ class MonitoringWizard extends Wizard implements SetupWizard
{ {
if ($page->getName() === 'setup_requirements') { if ($page->getName() === 'setup_requirements') {
$page->setRequirements($this->getRequirements()); $page->setRequirements($this->getRequirements());
} elseif ($page->getName() === 'setup_summary') { } elseif ($page->getName() === 'setup_monitoring_summary') {
$page->setSummary($this->getSetup()->getSummary()); $page->setSummary($this->getSetup()->getSummary());
$page->setSubjectTitle(mt('monitoring', 'the monitoring module', 'setup.summary.subject')); $page->setSubjectTitle(mt('monitoring', 'the monitoring module', 'setup.summary.subject'));
} elseif ( } elseif (
@ -79,23 +76,7 @@ class MonitoringWizard extends Wizard implements SetupWizard
$skip = $backendData['type'] !== 'livestatus'; $skip = $backendData['type'] !== 'livestatus';
} }
if ($skip) { return $skip ? $this->skipPage($newPage) : $newPage;
if ($this->hasPageData($newPage->getName())) {
$pageData = & $this->getPageData();
unset($pageData[$newPage->getName()]);
}
$pages = $this->getPages();
if ($this->getDirection() === static::FORWARD) {
$nextPage = $pages[array_search($newPage, $pages, true) + 1];
$newPage = $this->getNewPage($nextPage->getName(), $newPage);
} else { // $this->getDirection() === static::BACKWARD
$previousPage = $pages[array_search($newPage, $pages, true) - 1];
$newPage = $this->getNewPage($previousPage->getName(), $newPage);
}
}
return $newPage;
} }
/** /**
@ -125,8 +106,6 @@ class MonitoringWizard extends Wizard implements SetupWizard
$pageData = $this->getPageData(); $pageData = $this->getPageData();
$setup = new Setup(); $setup = new Setup();
$setup->addStep(new MakeDirStep(array(Icinga::app()->getConfigDir() . '/modules/monitoring'), 2770));
$setup->addStep( $setup->addStep(
new BackendStep(array( new BackendStep(array(
'backendConfig' => $pageData['setup_monitoring_backend'], 'backendConfig' => $pageData['setup_monitoring_backend'],
@ -148,8 +127,6 @@ class MonitoringWizard extends Wizard implements SetupWizard
)) ))
); );
$setup->addStep(new EnableModuleStep('monitoring'));
return $setup; return $setup;
} }

View File

@ -4,22 +4,13 @@
namespace Icinga\Module\Setup\Forms; namespace Icinga\Module\Setup\Forms;
use InvalidArgumentException;
use Icinga\Application\Icinga; use Icinga\Application\Icinga;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Session;
use Icinga\Web\Request;
class ModulePage extends Form class ModulePage extends Form
{ {
protected $session;
protected $wizards;
protected $modules; protected $modules;
protected $pageData;
protected $modulePaths; protected $modulePaths;
/** /**
@ -29,7 +20,6 @@ class ModulePage extends Form
{ {
$this->setName('setup_modules'); $this->setName('setup_modules');
$this->setViewScript('form/setup-modules.phtml'); $this->setViewScript('form/setup-modules.phtml');
$this->session = Session::getSession()->getNamespace(get_class($this));
$this->modulePaths = array(); $this->modulePaths = array();
if (($appModulePath = realpath(Icinga::app()->getApplicationDir() . '/../modules')) !== false) { if (($appModulePath = realpath(Icinga::app()->getApplicationDir() . '/../modules')) !== false) {
@ -37,84 +27,24 @@ class ModulePage extends Form
} }
} }
public function setPageData(array $pageData) public function createElements(array $formData)
{ {
$this->pageData = $pageData; foreach ($this->getModules() as $module) {
return $this; $this->addElement(
} 'checkbox',
$module->getName(),
public function handleRequest(Request $request = null) array(
{ 'required' => true,
$isPost = strtolower($request->getMethod()) === 'post'; 'description' => $module->getDescription(),
if ($isPost && $this->wasSent($request->getPost())) { 'label' => ucfirst($module->getName()),
if (($newModule = $request->getPost('module')) !== null) { 'value' => $module->getName() === 'monitoring' ? 1 : 0,
$this->setCurrentModule($newModule); 'decorators' => array('ViewHelper')
$this->getResponse()->redirectAndExit($this->getRedirectUrl()); )
} else { );
// The user submitted this form but with the parent wizard's navigation
// buttons so it's now up to the parent wizard to handle the request..
}
} else {
$wizard = $this->getCurrentWizard();
$wizardPage = $wizard->getCurrentPage();
$wizard->handleRequest($request);
if ($isPost && $wizard->isFinished() && $wizardPage->wasSent($request->getPost())) {
$wizards = $this->getWizards();
$newModule = null;
foreach ($wizards as $moduleName => $moduleWizard) {
if (false === $moduleWizard->isFinished()) {
$newModule = $moduleName;
}
}
if ($newModule === null) {
// In case all module wizards were completed just pick the first one again
reset($wizards);
$newModule = key($wizards);
}
$this->setCurrentModule($newModule);
}
} }
} }
public function clearSession() protected function getModules()
{
$this->session->clear();
foreach ($this->getWizards() as $wizard) {
$wizard->clearSession();
}
}
public function setCurrentModule($moduleName)
{
if (false === array_key_exists($moduleName, $this->getWizards())) {
throw new InvalidArgumentException(sprintf('Module "%s" does not provide a setup wizard', $moduleName));
}
$this->session->currentModule = $moduleName;
}
public function getCurrentModule()
{
$moduleName = $this->session->get('currentModule');
if ($moduleName === null) {
$moduleName = key($this->getWizards());
$this->setCurrentModule($moduleName);
}
return $moduleName;
}
public function getCurrentWizard()
{
$wizards = $this->getWizards();
return $wizards[$this->getCurrentModule()];
}
public function getModules()
{ {
if ($this->modules !== null) { if ($this->modules !== null) {
return $this->modules; return $this->modules;
@ -125,37 +55,39 @@ class ModulePage extends Form
$moduleManager = Icinga::app()->getModuleManager(); $moduleManager = Icinga::app()->getModuleManager();
$moduleManager->detectInstalledModules($this->modulePaths); $moduleManager->detectInstalledModules($this->modulePaths);
foreach ($moduleManager->listInstalledModules() as $moduleName) { foreach ($moduleManager->listInstalledModules() as $moduleName) {
$this->modules[] = $moduleManager->loadModule($moduleName)->getModule($moduleName); if ($moduleName !== 'setup') {
$this->modules[$moduleName] = $moduleManager->loadModule($moduleName)->getModule($moduleName);
}
} }
return $this->modules; return $this->modules;
} }
public function getWizards() public function getCheckedModules()
{ {
if ($this->wizards !== null) { $modules = $this->getModules();
return $this->wizards;
} else {
$this->wizards = array();
}
foreach ($this->getModules() as $module) { $checked = array();
if ($module->providesSetupWizard()) { foreach ($this->getElements() as $name => $element) {
$this->wizards[$module->getName()] = $module->getSetupWizard(); if (array_key_exists($name, $modules) && $element->isChecked()) {
$checked[$name] = $modules[$name];
} }
} }
$this->mergePageData($this->wizards); return $checked;
return $this->wizards;
} }
protected function mergePageData(array $wizards) public function getModuleWizards()
{ {
foreach ($wizards as $wizard) { $checked = $this->getCheckedModules();
$wizardPageData = & $wizard->getPageData();
foreach ($this->pageData as $pageName => $pageData) { $wizards = array();
$wizardPageData[$pageName] = $pageData; foreach ($checked as $name => $module) {
if ($module->providesSetupWizard()) {
$wizards[$name] = $module->getSetupWizard();
} }
} }
return $wizards;
} }
} }

View File

@ -4,6 +4,7 @@
namespace Icinga\Module\Setup\Forms; namespace Icinga\Module\Setup\Forms;
use LogicException;
use Icinga\Web\Form; use Icinga\Web\Form;
/** /**
@ -30,7 +31,12 @@ class SummaryPage extends Form
*/ */
public function init() public function init()
{ {
$this->setName('setup_summary'); if ($this->getName() === $this->filterName(get_class($this))) {
throw new LogicException(
'When utilizing ' . get_class($this) . ' it is required to set a unique name by using the form options'
);
}
$this->setViewScript('form/setup-summary.phtml'); $this->setViewScript('form/setup-summary.phtml');
} }

View File

@ -3,41 +3,18 @@
use Icinga\Web\Wizard; use Icinga\Web\Wizard;
?> ?>
<div class="module-menu"> <form id="<?= $form->getName(); ?>" name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>" action="<?= $form->getAction(); ?>">
<p><?= mt('setup', 'The following modules can be set up by using a web-based wizard as well. To setup a module, just complete its wizard and advance to the summary!'); ?></p> <h2><?= $this->translate('Modules', 'setup.page.title'); ?></h2>
<p><?= mt('setup', 'You can freely switch to a module\'s wizard by clicking its name below. The wizard you are currently looking at is written in bold. A small tick is shown on the right once a wizard has been completed.'); ?></p> <p><?= $this->translate('The following modules were found in your Icinga Web 2 installation. To enable and configure a module, just tick it and click "Next".'); ?></p>
<form name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>" action="<?= $form->getAction(); ?>"> <?php foreach ($form->getElements() as $element): ?>
<?= $form->getElement($form->getTokenElementName()); ?> <?php if (! in_array($element->getName(), array(Wizard::BTN_PREV, Wizard::BTN_NEXT, $form->getTokenElementName(), $form->getUidElementName()))): ?>
<?= $form->getElement($form->getUidElementName()); ?> <div class="module">
<ul> <h3><label for="<?= $element->getId(); ?>"><strong><?= $element->getLabel(); ?></strong></label></h3>
<?php $allFinished = true; ?> <label for="<?= $element->getId(); ?>"><?= $element->getDescription(); ?></label>
<?php foreach ($form->getModules() as $module): ?> <?= $element; ?>
<?php if ($module->providesSetupWizard()): ?> </div>
<li>
<?php $isActive = $module->getName() === $form->getCurrentModule(); ?>
<button type="submit" name="module" value="<?= $module->getName(); ?>">
<?= $isActive ? '<strong>' : '' ?><?= $module->getTitle(); ?><?= $isActive ? '</strong>' : '' ?>
</button>
<?php if ($module->getSetupWizard()->isFinished()): ?>
<?= $this->icon('ok', mt('setup', 'Completed', 'setup.modules.wizard.state')); ?>
<?php else: ?>
<?php $allFinished = false; ?>
<?php endif ?>
</li>
<?php endif ?>
<?php endforeach ?>
</ul>
</form>
<?php if ($allFinished): ?>
<p class="all-completed"><?= mt('setup', 'You\'ve completed all module wizards!'); ?></p>
<?php else: ?>
<p style="font-size: 80%;"><?= mt('setup', 'Note that you can skip a specific module by just not completing its wizard.'); ?></p>
<?php endif ?> <?php endif ?>
</div> <?php endforeach ?>
<div class="module-wizard">
<?= $form->getCurrentWizard()->getForm()->render(); ?>
</div>
<form name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>" action="<?= $form->getAction(); ?>">
<?= $form->getElement($form->getTokenElementName()); ?> <?= $form->getElement($form->getTokenElementName()); ?>
<?= $form->getElement($form->getUidElementName()); ?> <?= $form->getElement($form->getUidElementName()); ?>
<div class="buttons"> <div class="buttons">

View File

@ -11,7 +11,17 @@ $requirements = $form->getRequirements();
<?php foreach ($requirements as $requirement): ?> <?php foreach ($requirements as $requirement): ?>
<tr> <tr>
<td><h2><?= $requirement->title; ?></h2></td> <td><h2><?= $requirement->title; ?></h2></td>
<td style="width: 50%"><?= $requirement->description; ?></td> <td style="width: 50%">
<?php if (is_array($requirement->description)): ?>
<ul>
<?php foreach ($requirement->description as $desc): ?>
<li><?= $desc; ?></li>
<?php endforeach ?>
</ul>
<?php else: ?>
<?= $requirement->description; ?>
<?php endif ?>
</td>
<td class="state <?= $requirement->state === Requirements::STATE_OK ? 'fulfilled' : ( <td class="state <?= $requirement->state === Requirements::STATE_OK ? 'fulfilled' : (
$requirement->state === Requirements::STATE_OPTIONAL ? 'not-available' : 'missing' $requirement->state === Requirements::STATE_OPTIONAL ? 'not-available' : 'missing'
); ?>"><?= $requirement->message; ?></td> ); ?>"><?= $requirement->message; ?></td>
@ -22,7 +32,7 @@ $requirements = $form->getRequirements();
<td></td> <td></td>
<td class="btn-update"> <td class="btn-update">
<div class="buttons"> <div class="buttons">
<a title="<?= $this->translate('You may also need to restart the web-server for the changes to take effect!'); ?>" href="<?= $this->href(); ?>" class="button-like"><?= mt('setup', 'Refresh'); ?></a> <a title="<?= $this->translate('You may also need to restart the web-server for the changes to take effect!'); ?>" href="<?= $this->href(); ?>" class="button-like"><?= $this->translate('Refresh'); ?></a>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -4,9 +4,8 @@ use Icinga\Web\Wizard;
?> ?>
<p><?= sprintf( <p><?= sprintf(
mt( $this->translate(
'setup', 'You\'ve configured %1$s successfully. You can review the changes supposed to be made before setting it up.'
'The wizard is now complete. You can review the changes supposed to be made before setting up %1$s.'
. ' Make sure that everything is correct (Feel free to navigate back to make any corrections!) so' . ' Make sure that everything is correct (Feel free to navigate back to make any corrections!) so'
. ' that you can start using %1$s right after it has successfully been set up.' . ' that you can start using %1$s right after it has successfully been set up.'
), ),
@ -21,7 +20,7 @@ use Icinga\Web\Wizard;
<?php endif ?> <?php endif ?>
<?php endforeach ?> <?php endforeach ?>
</div> </div>
<form id="<?= $form->getName(); ?>" name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>" action="<?= $form->getAction(); ?>"> <form id="<?= $form->getName(); ?>" name="<?= $form->getName(); ?>" enctype="<?= $form->getEncType(); ?>" method="<?= $form->getMethod(); ?>" action="<?= $form->getAction(); ?>" class="summary">
<?= $form->getElement($form->getTokenElementName()); ?> <?= $form->getElement($form->getTokenElementName()); ?>
<?= $form->getElement($form->getUidElementName()); ?> <?= $form->getElement($form->getUidElementName()); ?>
<div class="buttons"> <div class="buttons">

View File

@ -11,16 +11,14 @@ $cliPath = realpath(Icinga::app()->getApplicationDir() . '/../bin/icingacli');
?> ?>
<div class="welcome-page"> <div class="welcome-page">
<h2><?= mt('setup', 'Welcome to the configuration of Icinga Web 2!') ?></h2> <h2><?= $this->translate('Welcome to the configuration of Icinga Web 2!') ?></h2>
<?php if (false === file_exists($setupTokenPath) && file_exists(Config::resolvePath('config.ini'))): ?> <?php if (false === file_exists($setupTokenPath) && file_exists(Config::resolvePath('config.ini'))): ?>
<p class="restart-warning"><?= mt( <p class="restart-warning"><?= $this->translate(
'setup',
'You\'ve already completed the configuration of Icinga Web 2. Note that most of your configuration' 'You\'ve already completed the configuration of Icinga Web 2. Note that most of your configuration'
. ' files will be overwritten in case you\'ll re-configure Icinga Web 2 using this wizard!' . ' files will be overwritten in case you\'ll re-configure Icinga Web 2 using this wizard!'
); ?></p> ); ?></p>
<?php else: ?> <?php else: ?>
<p><?= mt( <p><?= $this->translate(
'setup',
'This wizard will guide you through the configuration of Icinga Web 2. Once completed and successfully' 'This wizard will guide you through the configuration of Icinga Web 2. Once completed and successfully'
. ' finished you are able to log in and to explore all the new and stunning features!' . ' finished you are able to log in and to explore all the new and stunning features!'
); ?></p> ); ?></p>
@ -39,23 +37,22 @@ $cliPath = realpath(Icinga::app()->getApplicationDir() . '/../bin/icingacli');
</div> </div>
<div> <div>
<p><?= <p><?=
mt( $this->translate(
'setup',
'To run this wizard a user needs to authenticate using a token which is usually' 'To run this wizard a user needs to authenticate using a token which is usually'
. ' provided to him by an administrator who\'d followed the instructions below.' . ' provided to him by an administrator who\'d followed the instructions below.'
); ?></p> ); ?></p>
<p><?= mt('setup', 'If you\'ve got the IcingaCLI installed you can do the following:'); ?></p> <p><?= $this->translate('If you\'ve got the IcingaCLI installed you can do the following:'); ?></p>
<div class="code"> <div class="code">
<span><?= $cliPath ? $cliPath : 'icingacli'; ?> setup config directory --group <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_group'; ?><?= $configDir !== '/etc/icingaweb2' ? ' --config ' . $configDir : ''; ?>;</span> <span><?= $cliPath ? $cliPath : 'icingacli'; ?> setup config directory --group <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_group'; ?><?= $configDir !== '/etc/icingaweb2' ? ' --config ' . $configDir : ''; ?>;</span>
<span><?= $cliPath ? $cliPath : 'icingacli'; ?> setup token create;</span> <span><?= $cliPath ? $cliPath : 'icingacli'; ?> setup token create;</span>
</div> </div>
<p><?= mt('setup', 'In case the IcingaCLI is missing you can create the token manually:'); ?></p> <p><?= $this->translate('In case the IcingaCLI is missing you can create the token manually:'); ?></p>
<div class="code"> <div class="code">
<span>su <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_user'; ?> -c "mkdir -m 2770 <?= dirname($setupTokenPath); ?>; head -c 12 /dev/urandom | base64 | tee <?= $setupTokenPath; ?>; chmod 0660 <?= $setupTokenPath; ?>;";</span> <span>su <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_user'; ?> -c "mkdir -m 2770 <?= dirname($setupTokenPath); ?>; head -c 12 /dev/urandom | base64 | tee <?= $setupTokenPath; ?>; chmod 0660 <?= $setupTokenPath; ?>;";</span>
</div> </div>
<p><?= sprintf( <p><?= sprintf(
mt('setup', 'Please see the %s for an extensive description on how to access and use this wizard.'), $this->translate('Please see the %s for an extensive description on how to access and use this wizard.'),
'<a href="http://docs.icinga.org/">' . mt('setup', 'Icinga Web 2 documentation') . '</a>' // TODO: Add link to iw2 docs which points to the installation topic '<a href="http://docs.icinga.org/">' . $this->translate('Icinga Web 2 documentation') . '</a>' // TODO: Add link to iw2 docs which points to the installation topic
); ?></p> ); ?></p>
</div> </div>
</div> </div>

View File

@ -4,7 +4,7 @@ use Icinga\Web\Notification;
$pages = $wizard->getPages(); $pages = $wizard->getPages();
$finished = isset($success); $finished = isset($success);
$configPages = array_slice($pages, 2, count($pages) - 4, true); $configPages = array_slice($pages, 3, count($pages) - 1, true);
$currentPos = array_search($wizard->getCurrentPage(), $pages, true); $currentPos = array_search($wizard->getCurrentPage(), $pages, true);
list($configPagesLeft, $configPagesRight) = array_chunk($configPages, count($configPages) / 2, true); list($configPagesLeft, $configPagesRight) = array_chunk($configPages, count($configPages) / 2, true);
@ -30,7 +30,7 @@ if ($notifications->hasMessages()) {
<?= $this->img('img/logo_icinga_big.png'); ?> <?= $this->img('img/logo_icinga_big.png'); ?>
<div class="progress-bar"> <div class="progress-bar">
<div class="step" style="width: 10%;"> <div class="step" style="width: 10%;">
<h1><?= mt('setup', 'Welcome', 'setup.progress'); ?></h1> <h1><?= $this->translate('Welcome', 'setup.progress'); ?></h1>
<?php $stateClass = $finished || $currentPos > 0 ? 'complete' : ( <?php $stateClass = $finished || $currentPos > 0 ? 'complete' : (
$maxProgress > 0 ? 'visited' : 'active' $maxProgress > 0 ? 'visited' : 'active'
); ?> ); ?>
@ -41,30 +41,43 @@ if ($notifications->hasMessages()) {
</tr></tbody></table> </tr></tbody></table>
</div> </div>
<div class="step" style="width: 10%;"> <div class="step" style="width: 10%;">
<h1><?= mt('setup', 'Requirements', 'setup.progress'); ?></h1> <h1><?= $this->translate('Modules', 'setup.progress'); ?></h1>
<?php $stateClass = $finished || $currentPos > 1 ? ' complete' : ( <?php $stateClass = $finished || $currentPos > 1 ? ' complete' : (
$maxProgress > 1 ? ' visited' : ( $maxProgress > 1 ? ' visited' : (
$currentPos === 1 ? ' active' : '' $currentPos === 1 ? ' active' : ''
) )
); ?> ); ?>
<table><tbody><tr>
<td class="left"><div class="line left<?= $stateClass; ?>"></div></td>
<td class="middle"><div class="bubble <?= $stateClass; ?>"></div></td>
<td class="right"><div class="line right <?= $stateClass; ?>"></div></td>
</tr></tbody></table>
</div>
<div class="step" style="width: 10%;">
<h1><?= $this->translate('Requirements', 'setup.progress'); ?></h1>
<?php $stateClass = $finished || $currentPos > 2 ? ' complete' : (
$maxProgress > 2 ? ' visited' : (
$currentPos === 2 ? ' active' : ''
)
); ?>
<table><tbody><tr> <table><tbody><tr>
<td class="left"><div class="line left<?= $stateClass; ?>"></div></td> <td class="left"><div class="line left<?= $stateClass; ?>"></div></td>
<td class="middle"><div class="bubble<?= $stateClass; ?>"></div></td> <td class="middle"><div class="bubble<?= $stateClass; ?>"></div></td>
<td class="right"><div class="line right<?= $stateClass; ?>"></div></td> <td class="right"><div class="line right<?= $stateClass; ?>"></div></td>
</tr></tbody></table> </tr></tbody></table>
</div> </div>
<div class="step" style="width: 50%;"> <div class="step" style="width: 60%;">
<h1><?= mt('setup', 'Configuration', 'setup.progress'); ?></h1> <h1><?= $this->translate('Configuration', 'setup.progress'); ?></h1>
<table><tbody><tr> <table><tbody><tr>
<td class="left"> <td class="left">
<?php <?php
$firstPage = current($configPagesLeft); $firstPage = current($configPagesLeft);
$lastPage = end($configPagesLeft); $lastPage = end($configPagesLeft);
$lineWidth = round(100 / count($configPagesLeft), 2, PHP_ROUND_HALF_DOWN); $lineWidth = sprintf('%.2F', round(100 / count($configPagesLeft), 2, PHP_ROUND_HALF_DOWN));
?> ?>
<?php foreach ($configPagesLeft as $pos => $page): ?> <?php foreach ($configPagesLeft as $pos => $page): ?>
<?php $stateClass = $finished || $pos < $currentPos ? ' complete' : ( <?php $stateClass = $finished || $pos < $currentPos ? ' complete' : (
$pos < $maxProgress ? ' visited' : ($currentPos > 1 ? ' active' : '') $pos < $maxProgress ? ' visited' : ($currentPos > 2 ? ' active' : '')
); ?> ); ?>
<?php if ($page === $firstPage): ?> <?php if ($page === $firstPage): ?>
<div class="line left<?= $stateClass; ?>" style="float: left; width: <?= $lineWidth; ?>%; margin-right: 0"></div> <div class="line left<?= $stateClass; ?>" style="float: left; width: <?= $lineWidth; ?>%; margin-right: 0"></div>
@ -78,7 +91,7 @@ if ($notifications->hasMessages()) {
<td class="middle"> <td class="middle">
<div class="bubble<?= array_key_exists($currentPos, $configPagesLeft) ? ( <div class="bubble<?= array_key_exists($currentPos, $configPagesLeft) ? (
key($configPagesRight) <= $maxProgress ? ' visited' : ' active') : ( key($configPagesRight) <= $maxProgress ? ' visited' : ' active') : (
$finished || $currentPos > 1 ? ' complete' : ( $finished || $currentPos > 2 ? ' complete' : (
key($configPagesRight) < $maxProgress ? ' visited' : '' key($configPagesRight) < $maxProgress ? ' visited' : ''
) )
); ?>"></div> ); ?>"></div>
@ -87,11 +100,11 @@ if ($notifications->hasMessages()) {
<?php <?php
$firstPage = current($configPagesRight); $firstPage = current($configPagesRight);
$lastPage = end($configPagesRight); $lastPage = end($configPagesRight);
$lineWidth = round(100 / count($configPagesRight), 2, PHP_ROUND_HALF_DOWN); $lineWidth = sprintf('%.2F', round(100 / count($configPagesRight), 2, PHP_ROUND_HALF_DOWN));
?> ?>
<?php foreach ($configPagesRight as $pos => $page): ?> <?php foreach ($configPagesRight as $pos => $page): ?>
<?php $stateClass = $finished || $pos < $currentPos ? ' complete' : ( <?php $stateClass = $finished || $pos < $currentPos ? ' complete' : (
$pos < $maxProgress ? ' visited' : ($currentPos > 1 ? ' active' : '') $pos < $maxProgress ? ' visited' : ($currentPos > 2 ? ' active' : '')
); ?> ); ?>
<?php if ($page === $firstPage): ?> <?php if ($page === $firstPage): ?>
<div class="line<?= $stateClass; ?>" style="float: left; width: <?= $lineWidth; ?>%; margin-left: -0.1em;"></div> <div class="line<?= $stateClass; ?>" style="float: left; width: <?= $lineWidth; ?>%; margin-left: -0.1em;"></div>
@ -105,27 +118,7 @@ if ($notifications->hasMessages()) {
</tr></tbody></table> </tr></tbody></table>
</div> </div>
<div class="step" style="width: 10%;"> <div class="step" style="width: 10%;">
<h1><?= mt('setup', 'Modules', 'setup.progress'); ?></h1> <h1><?= $this->translate('Finish', 'setup.progress'); ?></h1>
<?php $stateClass = $finished || $currentPos > count($pages) - 2 ? ' complete' : (
$maxProgress > count($pages) - 2 ? ' visited' : ($currentPos === count($pages) - 2 ? ' active' : '')
); ?>
<table><tbody><tr>
<td class="left"><div class="line left<?= $stateClass; ?>"></div></td>
<td class="middle"><div class="bubble<?= $stateClass; ?>"></div></td>
<td class="right"><div class="line right<?= $stateClass; ?>"></div></td>
</tr></tbody></table>
</div>
<div class="step" style="width: 10%;">
<h1><?= mt('setup', 'Summary', 'setup.progress'); ?></h1>
<?php $stateClass = $finished ? ' complete' : ($currentPos === count($pages) - 1 ? ' active' : ''); ?>
<table><tbody><tr>
<td class="left"><div class="line left<?= $stateClass; ?>"></div></td>
<td class="middle"><div class="bubble<?= $stateClass; ?>"></div></td>
<td class="right"><div class="line right<?= $stateClass; ?>"></div></td>
</tr></tbody></table>
</div>
<div class="step" style="width: 10%;">
<h1><?= mt('setup', 'Finish', 'setup.progress'); ?></h1>
<?php $stateClass = $finished ? ' active' : ''; ?> <?php $stateClass = $finished ? ' active' : ''; ?>
<table><tbody><tr> <table><tbody><tr>
<td class="left"><div class="line left<?= $stateClass; ?>"></div></td> <td class="left"><div class="line left<?= $stateClass; ?>"></div></td>

View File

@ -11,16 +11,16 @@
<?php endif ?> <?php endif ?>
<?php endforeach ?> <?php endforeach ?>
<?php if ($success): ?> <?php if ($success): ?>
<p class="success"><?= mt('setup', 'Congratulations! Icinga Web 2 has been successfully set up.'); ?></p> <p class="success"><?= $this->translate('Congratulations! Icinga Web 2 has been successfully set up.'); ?></p>
<?php else: ?> <?php else: ?>
<p class="failure"><?= mt('setup', 'Sorry! Failed to set up Icinga Web 2 successfully.'); ?></p> <p class="failure"><?= $this->translate('Sorry! Failed to set up Icinga Web 2 successfully.'); ?></p>
<?php endif ?> <?php endif ?>
</div> </div>
<div class="buttons"> <div class="buttons">
<?php if ($success): ?> <?php if ($success): ?>
<a href="<?= $this->href('authentication/login'); ?>" class="button-like login"><?= mt('setup', 'Login to Icinga Web 2'); ?></a> <a href="<?= $this->href('authentication/login'); ?>" class="button-like login"><?= $this->translate('Login to Icinga Web 2'); ?></a>
<?php else: ?> <?php else: ?>
<a href="<?= $this->href(); ?>" class="button-like"><?= mt('setup', 'Back'); ?></a> <a href="<?= $this->href(); ?>" class="button-like"><?= $this->translate('Back'); ?></a>
<?php endif ?> <?php endif ?>
</div> </div>
</div> </div>

View File

@ -9,6 +9,9 @@ use IteratorAggregate;
/** /**
* Container to store and handle requirements * Container to store and handle requirements
*
* TODO: Requirements should be registered as objects with a specific purpose (PhpModRequirement, PhpIniRequirement, ..)
* so that it's not necessary to define unique identifiers which may differ between different modules.
*/ */
class Requirements implements IteratorAggregate class Requirements implements IteratorAggregate
{ {
@ -41,12 +44,40 @@ class Requirements implements IteratorAggregate
* *
* @return self * @return self
*/ */
public function add($requirement) public function add($name, $requirement)
{ {
$this->requirements[] = $requirement; $this->requirements[$name] = array_key_exists($name, $this->requirements)
? $this->combine($this->requirements[$name], $requirement)
: $requirement;
return $this; return $this;
} }
/**
* Combine the two given requirements
*
* Returns the most important requirement with the description from the other one being added.
*
* @param object $oldRequirement
* @param object $newRequirement
*
* @return object
*/
protected function combine($oldRequirement, $newRequirement)
{
if ($newRequirement->state === static::STATE_MANDATORY && $oldRequirement->state === static::STATE_OPTIONAL) {
$tempRequirement = $oldRequirement;
$oldRequirement = $newRequirement;
$newRequirement = $tempRequirement;
}
if (! is_array($oldRequirement->description)) {
$oldRequirement->description = array($oldRequirement->description);
}
$oldRequirement->description[] = $newRequirement->description;
return $oldRequirement;
}
/** /**
* Return all registered requirements * Return all registered requirements
* *
@ -70,6 +101,7 @@ class Requirements implements IteratorAggregate
/** /**
* Register an optional requirement * Register an optional requirement
* *
* @param string $name
* @param string $title * @param string $title
* @param string $description * @param string $description
* @param bool $state * @param bool $state
@ -77,20 +109,24 @@ class Requirements implements IteratorAggregate
* *
* @return self * @return self
*/ */
public function addOptional($title, $description, $state, $message) public function addOptional($name, $title, $description, $state, $message)
{ {
$this->add((object) array( $this->add(
'title' => $title, $name,
'message' => $message, (object) array(
'description' => $description, 'title' => $title,
'state' => (bool) $state ? static::STATE_OK : static::STATE_OPTIONAL 'message' => $message,
)); 'description' => $description,
'state' => (bool) $state ? static::STATE_OK : static::STATE_OPTIONAL
)
);
return $this; return $this;
} }
/** /**
* Register a mandatory requirement * Register a mandatory requirement
* *
* @param string $name
* @param string $title * @param string $title
* @param string $description * @param string $description
* @param bool $state * @param bool $state
@ -98,14 +134,17 @@ class Requirements implements IteratorAggregate
* *
* @return self * @return self
*/ */
public function addMandatory($title, $description, $state, $message) public function addMandatory($name, $title, $description, $state, $message)
{ {
$this->add((object) array( $this->add(
'title' => $title, $name,
'message' => $message, (object) array(
'description' => $description, 'title' => $title,
'state' => (bool) $state ? static::STATE_OK : static::STATE_MANDATORY 'message' => $message,
)); 'description' => $description,
'state' => (bool) $state ? static::STATE_OK : static::STATE_MANDATORY
)
);
return $this; return $this;
} }
@ -118,8 +157,8 @@ class Requirements implements IteratorAggregate
*/ */
public function merge(Requirements $requirements) public function merge(Requirements $requirements)
{ {
foreach ($requirements->getAll() as $requirement) { foreach ($requirements->getAll() as $name => $requirement) {
$this->add($requirement); $this->add($name, $requirement);
} }
return $this; return $this;

View File

@ -12,13 +12,13 @@ class EnableModuleStep extends Step
{ {
protected $modulePaths; protected $modulePaths;
protected $moduleName; protected $moduleNames;
protected $error; protected $errors;
public function __construct($moduleName) public function __construct(array $moduleNames)
{ {
$this->moduleName = $moduleName; $this->moduleNames = $moduleNames;
$this->modulePaths = array(); $this->modulePaths = array();
if (($appModulePath = realpath(Icinga::app()->getApplicationDir() . '/../modules')) !== false) { if (($appModulePath = realpath(Icinga::app()->getApplicationDir() . '/../modules')) !== false) {
@ -28,17 +28,20 @@ class EnableModuleStep extends Step
public function apply() public function apply()
{ {
try { $moduleManager = Icinga::app()->getModuleManager();
$moduleManager = Icinga::app()->getModuleManager(); $moduleManager->detectInstalledModules($this->modulePaths);
$moduleManager->detectInstalledModules($this->modulePaths);
$moduleManager->enableModule($this->moduleName); $success = true;
} catch (Exception $e) { foreach ($this->moduleNames as $moduleName) {
$this->error = $e; try {
return false; $moduleManager->enableModule($moduleName);
} catch (Exception $e) {
$this->errors[$moduleName] = $e;
$success = false;
}
} }
$this->error = false; return $success;
return true;
} }
public function getSummary() public function getSummary()
@ -48,12 +51,19 @@ class EnableModuleStep extends Step
public function getReport() public function getReport()
{ {
if ($this->error === false) { $okMessage = mt('setup', 'Module "%s" has been successfully enabled.');
return '<p>' . sprintf(mt('setup', 'Module "%s" has been successfully enabled.'), $this->moduleName) . '</p>'; $failMessage = mt('setup', 'Module "%s" could not be enabled. An error occured:');
} elseif ($this->error !== null) {
$message = mt('setup', 'Module "%s" could not be enabled. An error occured:'); $report = '';
return '<p class="error">' . sprintf($message, $this->moduleName) . '</p>' foreach ($this->moduleNames as $moduleName) {
. '<p>' . $this->error->getMessage() . '</p>'; if (isset($this->errors[$moduleName])) {
$report .= '<p class="error">' . sprintf($failMessage, $moduleName) . '</p>'
. '<p>' . $this->errors[$moduleName]->getMessage() . '</p>';
} else {
$report .= '<p>' . sprintf($okMessage, $moduleName) . '</p>';
}
} }
return $report;
} }
} }

View File

@ -29,6 +29,7 @@ use Icinga\Module\Setup\Steps\DatabaseStep;
use Icinga\Module\Setup\Steps\GeneralConfigStep; use Icinga\Module\Setup\Steps\GeneralConfigStep;
use Icinga\Module\Setup\Steps\ResourceStep; use Icinga\Module\Setup\Steps\ResourceStep;
use Icinga\Module\Setup\Steps\AuthenticationStep; use Icinga\Module\Setup\Steps\AuthenticationStep;
use Icinga\Module\Setup\Utils\EnableModuleStep;
use Icinga\Module\Setup\Utils\MakeDirStep; use Icinga\Module\Setup\Utils\MakeDirStep;
use Icinga\Module\Setup\Utils\DbTool; use Icinga\Module\Setup\Utils\DbTool;
@ -83,6 +84,7 @@ class WebWizard extends Wizard implements SetupWizard
protected function init() protected function init()
{ {
$this->addPage(new WelcomePage()); $this->addPage(new WelcomePage());
$this->addPage(new ModulePage());
$this->addPage(new RequirementsPage()); $this->addPage(new RequirementsPage());
$this->addPage(new AuthenticationPage()); $this->addPage(new AuthenticationPage());
$this->addPage(new PreferencesPage()); $this->addPage(new PreferencesPage());
@ -94,8 +96,14 @@ class WebWizard extends Wizard implements SetupWizard
$this->addPage(new AdminAccountPage()); $this->addPage(new AdminAccountPage());
$this->addPage(new GeneralConfigPage()); $this->addPage(new GeneralConfigPage());
$this->addPage(new DatabaseCreationPage()); $this->addPage(new DatabaseCreationPage());
$this->addPage(new ModulePage()); $this->addPage(new SummaryPage(array('name' => 'setup_summary')));
$this->addPage(new SummaryPage());
if (($modulePageData = $this->getPageData('setup_modules')) !== null) {
$modulePage = $this->getPage('setup_modules')->populate($modulePageData);
foreach ($modulePage->getModuleWizards() as $moduleWizard) {
$this->addPage($moduleWizard);
}
}
} }
/** /**
@ -167,9 +175,6 @@ class WebWizard extends Wizard implements SetupWizard
unset($pageData['setup_admin_account']); unset($pageData['setup_admin_account']);
unset($pageData['setup_authentication_backend']); unset($pageData['setup_authentication_backend']);
} }
} elseif ($page->getName() === 'setup_modules') {
$page->setPageData($this->getPageData());
$page->handleRequest($request);
} }
} }
@ -222,23 +227,7 @@ class WebWizard extends Wizard implements SetupWizard
} }
} }
if ($skip) { return $skip ? $this->skipPage($newPage) : $newPage;
if ($this->hasPageData($newPage->getName())) {
$pageData = & $this->getPageData();
unset($pageData[$newPage->getName()]);
}
$pages = $this->getPages();
if ($this->getDirection() === static::FORWARD) {
$nextPage = $pages[array_search($newPage, $pages, true) + 1];
$newPage = $this->getNewPage($nextPage->getName(), $newPage);
} else { // $this->getDirection() === static::BACKWARD
$previousPage = $pages[array_search($newPage, $pages, true) - 1];
$newPage = $this->getNewPage($previousPage->getName(), $newPage);
}
}
return $newPage;
} }
/** /**
@ -263,7 +252,6 @@ class WebWizard extends Wizard implements SetupWizard
public function clearSession() public function clearSession()
{ {
parent::clearSession(); parent::clearSession();
$this->getPage('setup_modules')->clearSession();
$tokenPath = Config::resolvePath('setup.token'); $tokenPath = Config::resolvePath('setup.token');
if (file_exists($tokenPath)) { if (file_exists($tokenPath)) {
@ -297,7 +285,7 @@ class WebWizard extends Wizard implements SetupWizard
? $pageData['setup_database_creation']['password'] ? $pageData['setup_database_creation']['password']
: null, : null,
'schemaPath' => Config::module('setup') 'schemaPath' => Config::module('setup')
->get('schema', 'path', Icinga::app()->getBaseDir('etc/schema')) ->get('schema', 'path', Icinga::app()->getBaseDir('etc' . DIRECTORY_SEPARATOR . 'schema'))
)) ))
); );
} }
@ -350,20 +338,22 @@ class WebWizard extends Wizard implements SetupWizard
$setup->addStep( $setup->addStep(
new MakeDirStep( new MakeDirStep(
array( array(
$configDir . '/modules', $configDir . DIRECTORY_SEPARATOR . 'modules',
$configDir . '/preferences', $configDir . DIRECTORY_SEPARATOR . 'preferences',
$configDir . '/enabledModules' $configDir . DIRECTORY_SEPARATOR . 'enabledModules'
), ),
2770 2770
) )
); );
foreach ($this->getPage('setup_modules')->setPageData($this->getPageData())->getWizards() as $wizard) { foreach ($this->getWizards() as $wizard) {
if ($wizard->isFinished()) { if ($wizard->isComplete()) {
$setup->addSteps($wizard->getSetup()->getSteps()); $setup->addSteps($wizard->getSetup()->getSteps());
} }
} }
$setup->addStep(new EnableModuleStep(array_keys($this->getPage('setup_modules')->getCheckedModules())));
return $setup; return $setup;
} }
@ -376,6 +366,7 @@ class WebWizard extends Wizard implements SetupWizard
$phpVersion = Platform::getPhpVersion(); $phpVersion = Platform::getPhpVersion();
$requirements->addMandatory( $requirements->addMandatory(
'php_version_>=_5_3_2',
mt('setup', 'PHP Version'), mt('setup', 'PHP Version'),
mt( mt(
'setup', 'setup',
@ -388,6 +379,7 @@ class WebWizard extends Wizard implements SetupWizard
$defaultTimezone = Platform::getPhpConfig('date.timezone'); $defaultTimezone = Platform::getPhpConfig('date.timezone');
$requirements->addMandatory( $requirements->addMandatory(
'existing_default_timezone',
mt('setup', 'Default Timezone'), mt('setup', 'Default Timezone'),
sprintf( sprintf(
mt('setup', 'It is required that a default timezone has been set using date.timezone in %s.'), mt('setup', 'It is required that a default timezone has been set using date.timezone in %s.'),
@ -400,6 +392,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'platform=linux',
mt('setup', 'Linux Platform'), mt('setup', 'Linux Platform'),
mt( mt(
'setup', 'setup',
@ -411,6 +404,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addMandatory( $requirements->addMandatory(
'existing_php_mod_openssl',
mt('setup', 'PHP Module: OpenSSL'), mt('setup', 'PHP Module: OpenSSL'),
mt('setup', 'The PHP module for OpenSSL is required to generate cryptographically safe password salts.'), mt('setup', 'The PHP module for OpenSSL is required to generate cryptographically safe password salts.'),
Platform::extensionLoaded('openssl'), Platform::extensionLoaded('openssl'),
@ -420,6 +414,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_json',
mt('setup', 'PHP Module: JSON'), mt('setup', 'PHP Module: JSON'),
mt('setup', 'The JSON module for PHP is required for various export functionalities as well as APIs.'), mt('setup', 'The JSON module for PHP is required for various export functionalities as well as APIs.'),
Platform::extensionLoaded('json'), Platform::extensionLoaded('json'),
@ -429,6 +424,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_ldap',
mt('setup', 'PHP Module: LDAP'), mt('setup', 'PHP Module: LDAP'),
mt('setup', 'If you\'d like to authenticate users using LDAP the corresponding PHP module is required'), mt('setup', 'If you\'d like to authenticate users using LDAP the corresponding PHP module is required'),
Platform::extensionLoaded('ldap'), Platform::extensionLoaded('ldap'),
@ -438,6 +434,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_intl',
mt('setup', 'PHP Module: INTL'), mt('setup', 'PHP Module: INTL'),
mt( mt(
'setup', 'setup',
@ -452,6 +449,7 @@ class WebWizard extends Wizard implements SetupWizard
// TODO(6172): Remove this requirement once we do not ship dompdf with Icinga Web 2 anymore // TODO(6172): Remove this requirement once we do not ship dompdf with Icinga Web 2 anymore
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_dom',
mt('setup', 'PHP Module: DOM'), mt('setup', 'PHP Module: DOM'),
mt('setup', 'To be able to export views and reports to PDF, the DOM module for PHP is required.'), mt('setup', 'To be able to export views and reports to PDF, the DOM module for PHP is required.'),
Platform::extensionLoaded('dom'), Platform::extensionLoaded('dom'),
@ -461,6 +459,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_gd',
mt('setup', 'PHP Module: GD'), mt('setup', 'PHP Module: GD'),
mt( mt(
'setup', 'setup',
@ -474,6 +473,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_imagick',
mt('setup', 'PHP Module: Imagick'), mt('setup', 'PHP Module: Imagick'),
mt( mt(
'setup', 'setup',
@ -487,6 +487,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_pdo_mysql',
mt('setup', 'PHP Module: PDO-MySQL'), mt('setup', 'PHP Module: PDO-MySQL'),
mt( mt(
'setup', 'setup',
@ -499,6 +500,7 @@ class WebWizard extends Wizard implements SetupWizard
); );
$requirements->addOptional( $requirements->addOptional(
'existing_php_mod_pdo_pgsql',
mt('setup', 'PHP Module: PDO-PostgreSQL'), mt('setup', 'PHP Module: PDO-PostgreSQL'),
mt( mt(
'setup', 'setup',
@ -513,6 +515,7 @@ class WebWizard extends Wizard implements SetupWizard
$mysqlAdapterFound = Platform::zendClassExists('Zend_Db_Adapter_Pdo_Mysql'); $mysqlAdapterFound = Platform::zendClassExists('Zend_Db_Adapter_Pdo_Mysql');
$requirements->addOptional( $requirements->addOptional(
'existing_class_Zend_Db_Adapter_Pdo_Mysql',
mt('setup', 'Zend Database Adapter For MySQL'), mt('setup', 'Zend Database Adapter For MySQL'),
mt('setup', 'The Zend database adapter for MySQL is required to access a MySQL database.'), mt('setup', 'The Zend database adapter for MySQL is required to access a MySQL database.'),
$mysqlAdapterFound, $mysqlAdapterFound,
@ -523,6 +526,7 @@ class WebWizard extends Wizard implements SetupWizard
$pgsqlAdapterFound = Platform::zendClassExists('Zend_Db_Adapter_Pdo_Pgsql'); $pgsqlAdapterFound = Platform::zendClassExists('Zend_Db_Adapter_Pdo_Pgsql');
$requirements->addOptional( $requirements->addOptional(
'existing_class_Zend_Db_Adapter_Pdo_Pgsql',
mt('setup', 'Zend Database Adapter For PostgreSQL'), mt('setup', 'Zend Database Adapter For PostgreSQL'),
mt('setup', 'The Zend database adapter for PostgreSQL is required to access a PostgreSQL database.'), mt('setup', 'The Zend database adapter for PostgreSQL is required to access a PostgreSQL database.'),
$pgsqlAdapterFound, $pgsqlAdapterFound,
@ -533,6 +537,7 @@ class WebWizard extends Wizard implements SetupWizard
$configDir = Icinga::app()->getConfigDir(); $configDir = Icinga::app()->getConfigDir();
$requirements->addMandatory( $requirements->addMandatory(
'writable_directory_' . $configDir,
mt('setup', 'Writable Config Directory'), mt('setup', 'Writable Config Directory'),
mt( mt(
'setup', 'setup',
@ -548,8 +553,8 @@ class WebWizard extends Wizard implements SetupWizard
) )
); );
foreach ($this->getPage('setup_modules')->setPageData($this->getPageData())->getWizards() as $wizard) { foreach ($this->getWizards() as $wizard) {
$requirements->merge($wizard->getRequirements()->allOptional()); $requirements->merge($wizard->getRequirements());
} }
return $requirements; return $requirements;

View File

@ -176,6 +176,12 @@
margin: 0 1em 0 0; margin: 0 1em 0 0;
} }
ul {
margin: 0;
padding-left: 1em;
list-style-type: square;
}
&.state { &.state {
color: white; color: white;
padding: 0.4em; padding: 0.4em;
@ -270,7 +276,7 @@
} }
} }
form#setup_summary { form.summary {
clear: left; clear: left;
} }
} }
@ -395,71 +401,44 @@
} }
} }
#setup { #setup_modules {
div.module-wizard { div.module {
width: auto; float: left;
padding: 1em; width: 15em;
overflow: hidden; height: 15em;
border: solid 1px lightgrey; margin: 1em;
padding: 0.3em;
border: 1px solid #ccc;
background-color: snow;
div.buttons { h3 {
margin: 1.5em 0 0; border: none;
margin: 0.5em 0;
text-align: center;
label {
margin: 0;
width: 15em;
cursor: pointer;
}
}
h3 + label {
width: 13.5em;
height: 13.9em;
overflow: auto;
cursor: pointer;
font-weight: normal;
}
input[type=checkbox] {
height: 10em;
float: right; float: right;
button[type=submit] {
padding: 0.5em;
line-height: 0.5em;
background-color: @colorPetrol;
&:hover, &:focus, &:active {
background-color: #666;
}
}
} }
} }
div.module-menu { div.buttons {
font-size: 0.9em; padding-top: 1em;
width: 25%; clear: both;
float: right;
margin-left: 1.5em;
p {
margin-top: 0;
&.all-completed {
.conspicuous-state-notification;
text-align: center;
font-size: 90%;
background-color: @colorOk;
}
}
ul {
padding-left: 1.2em;
button {
margin: 0 0 0.8em;
padding: 0;
color: black;
border: none;
outline: none;
font-size: 90%;
background-color: white;
&:hover {
color: #666;
cursor: pointer;
}
&:focus, &:active {
color: #666;
}
}
img {
margin: 0 0.5em 0.2em;
}
}
} }
} }