mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-09-02 23:58:09 +02:00
566 lines
20 KiB
PHP
566 lines
20 KiB
PHP
<?php
|
|
|
|
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
|
|
|
namespace Icinga\Controllers;
|
|
|
|
use Icinga\Forms\Dashboard\HomeForm;
|
|
use Icinga\Forms\Dashboard\DashletForm;
|
|
use Icinga\Forms\Dashboard\PaneForm;
|
|
use Icinga\Forms\Dashboard\RemoveHomeForm;
|
|
use Icinga\Forms\Dashboard\RemoveDashletForm;
|
|
use Icinga\Forms\Dashboard\RemovePaneForm;
|
|
use Icinga\Forms\Dashboard\SetupNewDashboardForm;
|
|
use Icinga\Forms\Dashboard\WelcomeForm;
|
|
use Icinga\Util\Json;
|
|
use Icinga\Web\Dashboard\Dashboard;
|
|
use Icinga\Web\Dashboard\DashboardHome;
|
|
use Icinga\Web\Dashboard\Pane;
|
|
use Icinga\Web\Dashboard\Settings;
|
|
use Icinga\Web\Notification;
|
|
use Icinga\Web\Widget\Tabextension\DashboardSettings;
|
|
use ipl\Web\Compat\CompatController;
|
|
use ipl\Web\Url;
|
|
use ipl\Web\Widget\Icon;
|
|
use ipl\Web\Widget\Link;
|
|
|
|
/**
|
|
* Handles all kind of dashboard request actions
|
|
*
|
|
* See {@see Dashboard} for more information about dashboards
|
|
*/
|
|
class DashboardsController extends CompatController
|
|
{
|
|
/** @var Dashboard */
|
|
protected $dashboard;
|
|
|
|
/** @var string Whether the currently loaded home/pane is also loaded on the previous page */
|
|
protected $highlighted = null;
|
|
|
|
public function init()
|
|
{
|
|
parent::init();
|
|
|
|
// The "highlighted" param indicates whether this home/pane is currently being loaded in the
|
|
// DM view meanwhile rendering a modal view (update and remove actions). If it's indeed the case,
|
|
// we have to construct a proper http redirect after successfully removing this home/pane.
|
|
$this->highlighted = $this->params->shift('highlighted');
|
|
|
|
$this->dashboard = new Dashboard();
|
|
$this->dashboard->setUser($this->Auth()->getUser());
|
|
$this->dashboard->setTabs($this->getTabs());
|
|
}
|
|
|
|
public function indexAction()
|
|
{
|
|
$pane = $this->params->get('pane');
|
|
|
|
// If we don't load all dashboard homes here, the cog icon won't be rendered in the dashboard tabs
|
|
$this->dashboard->load(DashboardHome::DEFAULT_HOME, $pane, true);
|
|
|
|
$activeHome = $this->dashboard->getActiveEntry();
|
|
if (! $activeHome || ! $activeHome->hasEntries()) {
|
|
$this->addTitleTab(t('Welcome'));
|
|
|
|
// Setup dashboard introduction form
|
|
$welcomeForm = new WelcomeForm($this->dashboard);
|
|
$welcomeForm->on(WelcomeForm::ON_SUCCESS, function () use ($welcomeForm) {
|
|
$this->redirectNow($welcomeForm->getRedirectUrl());
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
$this->content->getAttributes()->add('class', 'welcome-view');
|
|
$this->dashboard->addHtml($welcomeForm);
|
|
}
|
|
|
|
$this->createTabs();
|
|
|
|
$this->addContent($this->dashboard);
|
|
}
|
|
|
|
/**
|
|
* Display all the dashboards assigned to a Home set in the `home` request param
|
|
*
|
|
* If no pane param is submitted, the default pane is displayed (usually the first one)
|
|
*/
|
|
public function homeAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
$pane = $this->params->get('pane');
|
|
|
|
$this->dashboard->load($home, $pane);
|
|
|
|
$activeHome = $this->dashboard->getActiveEntry();
|
|
if (! $activeHome->getEntries()) {
|
|
$this->addTitleTab($activeHome->getTitle());
|
|
}
|
|
|
|
// Not to render the cog icon before the above tab
|
|
$this->createTabs();
|
|
|
|
$this->addContent($this->dashboard);
|
|
}
|
|
|
|
public function newHomeAction()
|
|
{
|
|
$this->dashboard->load();
|
|
|
|
$homeForm = (new HomeForm($this->dashboard))
|
|
->on(HomeForm::ON_SUCCESS, function () {
|
|
$this->getResponse()
|
|
->setHeader('X-Icinga-Extra-Updates', '#menu')
|
|
->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
$this->addTitleTab(t('Add new Dashboard Home'));
|
|
$this->addContent($homeForm);
|
|
}
|
|
|
|
public function editHomeAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
|
|
$this->dashboard->load($home);
|
|
|
|
$homeForm = (new HomeForm($this->dashboard))
|
|
->on(HomeForm::ON_SUCCESS, function () {
|
|
$this->getResponse()
|
|
->setHeader('X-Icinga-Extra-Updates', '#menu')
|
|
->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$homeForm->load($this->dashboard->getActiveEntry());
|
|
|
|
$this->addTitleTab(t('Update Home'));
|
|
$this->addContent($homeForm);
|
|
}
|
|
|
|
public function removeHomeAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
|
|
$this->dashboard->load($home);
|
|
|
|
$homeForm = new RemoveHomeForm($this->dashboard);
|
|
$homeForm->on(RemoveHomeForm::ON_SUCCESS, function () use ($homeForm) {
|
|
$response = $this->getResponse();
|
|
$response->setHeader('X-Icinga-Extra-Updates', '#menu');
|
|
|
|
if ($this->highlighted && $homeForm->requestSucceeded()) {
|
|
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
|
} else {
|
|
$response->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
}
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$this->addTitleTab(t('Remove Home'));
|
|
$this->addContent($homeForm);
|
|
}
|
|
|
|
public function newPaneAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
|
|
$this->dashboard->load($home, null, true);
|
|
|
|
$paneForm = (new PaneForm($this->dashboard))
|
|
->on(PaneForm::ON_SUCCESS, function () {
|
|
$this->getResponse()->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$this->addTitleTab(t('Add new Pane'));
|
|
$this->addContent($paneForm);
|
|
}
|
|
|
|
public function editPaneAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
$pane = $this->params->getRequired('pane');
|
|
|
|
$this->dashboard->load($home, $pane, true);
|
|
|
|
$paneForm = new PaneForm($this->dashboard);
|
|
$paneForm->on(PaneForm::ON_SUCCESS, function () use ($paneForm, $home) {
|
|
if ($paneForm->requestSucceeded() && $this->highlighted && $home !== $paneForm->getValue('home')) {
|
|
$params = $this->params->without('pane');
|
|
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings')->setParams($params));
|
|
} else {
|
|
$this->getResponse()->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
}
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
$paneForm->load($this->dashboard->getActiveEntry()->getEntry($pane));
|
|
|
|
$this->addTitleTab(t('Update Pane'));
|
|
$this->addContent($paneForm);
|
|
}
|
|
|
|
public function removePaneAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
$paneParam = $this->params->getRequired('pane');
|
|
|
|
$this->dashboard->load($home, $paneParam);
|
|
|
|
$paneForm = new RemovePaneForm($this->dashboard);
|
|
$paneForm->populate(['org_name' => $paneParam]);
|
|
$paneForm->on(RemovePaneForm::ON_SUCCESS, function () use ($paneForm) {
|
|
if ($this->highlighted && $paneForm->requestSucceeded()) {
|
|
$params = $this->params->without('pane');
|
|
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings')->setParams($params));
|
|
} else {
|
|
$this->getResponse()->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
}
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
$this->addTitleTab(t('Remove Pane'));
|
|
$this->addContent($paneForm);
|
|
}
|
|
|
|
public function newDashletAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
$pane = $this->params->get('pane');
|
|
|
|
$this->dashboard->load($home, $pane, true);
|
|
|
|
$dashletForm = new DashletForm($this->dashboard);
|
|
$dashletForm->populate($this->getRequest()->getPost());
|
|
$dashletForm->on(DashletForm::ON_SUCCESS, function () {
|
|
$this->getResponse()->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
if (isset($this->getRequest()->getPost()['btn_next'])) {
|
|
$this->addTitleTab(t('Add Dashlet To Dashboard'));
|
|
} else {
|
|
$this->addTitleTab(t('Select Dashlets'));
|
|
}
|
|
|
|
$this->addContent($dashletForm);
|
|
}
|
|
|
|
public function addToDashletAction()
|
|
{
|
|
$this->dashboard->load(DashboardHome::DEFAULT_HOME, $this->params->get('pane'), true);
|
|
|
|
$dashletForm = new DashletForm($this->dashboard);
|
|
$dashletForm->populate([
|
|
'url' => rawurldecode($this->params->shift('url')),
|
|
'btn_next' => 'y'
|
|
]);
|
|
|
|
$dashletForm->on(DashletForm::ON_SUCCESS, function () {
|
|
$params = $this->params->without('dashlet');
|
|
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings')->setParams($params));
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
$this->addTitleTab(t('Add Dashlet To Dashboard'));
|
|
$this->addContent($dashletForm);
|
|
}
|
|
|
|
public function editDashletAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
$pane = $this->params->getRequired('pane');
|
|
$dashlet = $this->params->getRequired('dashlet');
|
|
|
|
$this->dashboard->load($home, $pane, true);
|
|
|
|
$pane = $this->dashboard->getActiveEntry()->getActiveEntry();
|
|
if (! $pane->hasEntry($dashlet)) {
|
|
$this->httpNotFound(t('Dashlet "%s" not found'), $dashlet);
|
|
}
|
|
|
|
$dashlet = $pane->getEntry($dashlet);
|
|
|
|
$dashletForm = (new DashletForm($this->dashboard))
|
|
->on(DashletForm::ON_SUCCESS, function () {
|
|
$this->getResponse()->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$dashletForm->load($dashlet);
|
|
|
|
$this->addTitleTab(t('Edit Dashlet'));
|
|
$this->addContent($dashletForm);
|
|
}
|
|
|
|
public function removeDashletAction()
|
|
{
|
|
$home = $this->params->getRequired('home');
|
|
$pane = $this->params->getRequired('pane');
|
|
$dashlet = $this->params->getRequired('dashlet');
|
|
|
|
$this->dashboard->load($home, $pane);
|
|
|
|
$pane = $this->dashboard->getActiveEntry()->getActiveEntry();
|
|
if (! $pane->hasEntry($dashlet)) {
|
|
$this->httpNotFound(t('Dashlet "%s" not found'), $dashlet);
|
|
}
|
|
|
|
$removeForm = (new RemoveDashletForm($this->dashboard))
|
|
->on(RemoveDashletForm::ON_SUCCESS, function () {
|
|
$this->getResponse()->setHeader('X-Icinga-Container', 'modal-content', true);
|
|
|
|
$this->redirectNow('__CLOSE__');
|
|
})
|
|
->handleRequest($this->getServerRequest());
|
|
|
|
$this->addTitleTab(t('Remove Dashlet'));
|
|
$this->addContent($removeForm);
|
|
}
|
|
|
|
/**
|
|
* Handles all widgets drag and drop requests
|
|
*/
|
|
public function reorderWidgetsAction()
|
|
{
|
|
$this->assertHttpMethod('post');
|
|
$dashboards = $this->getRequest()->getPost();
|
|
if (! isset($dashboards['dashboardData'])) {
|
|
$this->httpBadRequest(t('Invalid request data'));
|
|
}
|
|
|
|
$dashboards = Json::decode($dashboards['dashboardData'], true);
|
|
$originals = $dashboards['originals'];
|
|
$dashboardType = $dashboards['dashboardType'];
|
|
unset($dashboards['originals']);
|
|
unset($dashboards['dashboardType']);
|
|
|
|
$highlightHome = $this->params->get('home');
|
|
$highlightPane = $this->params->get('pane');
|
|
if (! $highlightHome) {
|
|
$highlightHome = DashboardHome::DEFAULT_HOME;
|
|
}
|
|
|
|
$this->dashboard->load($highlightHome, $highlightPane, true);
|
|
|
|
$redirect = false;
|
|
$orgHome = null;
|
|
$orgPane = null;
|
|
if ($originals && isset($originals['originalHome'])) {
|
|
/** @var DashboardHome $orgHome */
|
|
$orgHome = $this->dashboard->getEntry($originals['originalHome']);
|
|
$orgHome->loadDashboardEntries($originals['originalPane'] ?? null);
|
|
|
|
// We need to know the original pane only if it's a Dashlet Widget. In this case
|
|
// we don't care about the other entries of the original home
|
|
if (isset($originals['originalPane']) && $dashboardType === /** Keep this with JS in sync */ 'Dashlets') {
|
|
$orgPane = $orgHome->getEntry($originals['originalPane']);
|
|
$orgHome->setEntries([$orgPane->getName() => $orgPane]);
|
|
}
|
|
}
|
|
|
|
$duplicatedError = false;
|
|
foreach ($dashboards as $home => $value) {
|
|
if (! $this->dashboard->hasEntry($home)) {
|
|
Notification::error(sprintf(t('Dashboard home "%s" not found'), $home));
|
|
break;
|
|
}
|
|
|
|
$home = $this->dashboard->getEntry($home);
|
|
/** @var DashboardHome $home */
|
|
if (! is_array($value)) {
|
|
$this->dashboard->reorderWidget($home, (int) $value);
|
|
|
|
Notification::success(sprintf(t('Updated dashboard home "%s" successfully'), $home->getTitle()));
|
|
break;
|
|
}
|
|
|
|
$home->loadDashboardEntries();
|
|
foreach ($value as $pane => $indexOrValues) {
|
|
if (! $home->hasEntry($pane) && (! $orgHome || ! $orgHome->hasEntry($pane))) {
|
|
Notification::error(sprintf(t('Dashboard pane "%s" not found'), $pane));
|
|
break;
|
|
}
|
|
|
|
$pane = $home->hasEntry($pane) ? $home->getEntry($pane) : $orgHome->getEntry($pane);
|
|
/** @var Pane $pane */
|
|
$pane->loadDashboardEntries();
|
|
|
|
if (! is_array($indexOrValues)) {
|
|
if ($orgHome && $orgHome->hasEntry($pane->getName()) && $home->hasEntry($pane->getName())) {
|
|
Notification::error(sprintf(
|
|
t('Dashboard "%s" already exists within "%s" home'),
|
|
$pane->getTitle(),
|
|
$home->getTitle()
|
|
));
|
|
|
|
$duplicatedError = true;
|
|
break;
|
|
}
|
|
|
|
// Perform DB updates
|
|
$home->reorderWidget($pane, (int) $indexOrValues, $orgHome);
|
|
if ($orgHome) {
|
|
// In order to properly update the dashlets id (user + home + pane + dashlet)
|
|
$pane->manageEntry($pane->getEntries());
|
|
}
|
|
|
|
$redirect = $orgHome && $pane->getName() === $highlightPane;
|
|
|
|
Notification::success(
|
|
sprintf(t('%s pane "%s" successfully'), $orgHome ? 'Moved' : 'Updated', $pane->getTitle())
|
|
);
|
|
break;
|
|
}
|
|
|
|
foreach ($indexOrValues as $dashlet => $index) {
|
|
if (! $pane->hasEntry($dashlet) && (! $orgPane || ! $orgPane->hasEntry($dashlet))) {
|
|
Notification::error(sprintf(t('Dashlet "%s" not found'), $dashlet));
|
|
break;
|
|
}
|
|
|
|
if ($orgPane && $orgPane->hasEntry($dashlet) && $pane->hasEntry($dashlet)) {
|
|
Notification::error(sprintf(
|
|
t('Pane "%s" has already a Dashlet called "%s"'),
|
|
$pane->getTitle(),
|
|
$dashlet
|
|
));
|
|
|
|
$duplicatedError = true;
|
|
break;
|
|
}
|
|
|
|
$dashlet = $pane->hasEntry($dashlet) ? $pane->getEntry($dashlet) : $orgPane->getEntry($dashlet);
|
|
$pane->reorderWidget($dashlet, (int) $index, $orgPane);
|
|
|
|
Notification::success(sprintf(
|
|
t('%s dashlet "%s" successfully'),
|
|
$orgPane ? 'Moved' : 'Updated',
|
|
$dashlet->getTitle()
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
$params = clone $this->params;
|
|
if ($duplicatedError || $redirect) {
|
|
/**
|
|
* Even though the drop action couldn't be performed successfully from our server, Sortable JS has
|
|
* already dropped the draggable element though, so we need to redirect here to undo it.
|
|
*
|
|
* When the requested pane is being moved to another home we have to also redirect here in order to
|
|
* update state history correctly, because we can't load this pane from the requested home anymore
|
|
*/
|
|
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings')->setParams($params->without('pane')));
|
|
}
|
|
|
|
$this->createTabs();
|
|
$this->getTabs()->setRefreshUrl(Url::fromPath(Dashboard::BASE_ROUTE . '/settings')->setParams($params));
|
|
$this->dashboard->activate('dashboard_settings');
|
|
$this->sendMultipartUpdate();
|
|
}
|
|
|
|
/**
|
|
* Provides a mini wizard which guides a new user through the dashboard creation
|
|
* process and helps them get a first impression of Icinga Web 2.
|
|
*/
|
|
public function setupDashboardAction()
|
|
{
|
|
$this->dashboard->load(DashboardHome::DEFAULT_HOME);
|
|
|
|
$setupForm = new SetupNewDashboardForm($this->dashboard);
|
|
$setupForm->on(SetupNewDashboardForm::ON_SUCCESS, function () use ($setupForm) {
|
|
$this->redirectNow($setupForm->getRedirectUrl());
|
|
})->handleRequest($this->getServerRequest());
|
|
|
|
if (isset($this->getRequest()->getPost()['btn_next'])) {
|
|
// Set compact view to prevent the controls from being
|
|
// rendered in the modal view when redirecting
|
|
$this->view->compact = true;
|
|
|
|
$this->addTitleTab(t('Configure Dashlets'));
|
|
} else {
|
|
$this->addTitleTab(t('Add Dashlet'));
|
|
}
|
|
|
|
$this->addContent($setupForm);
|
|
}
|
|
|
|
public function settingsAction()
|
|
{
|
|
$highlightHome = $this->params->get('home');
|
|
$highlightPane = $this->params->get('pane');
|
|
if (! $highlightHome && $highlightPane) {
|
|
// A Dashboard Pane is always requested with home param unless it's part of the "Default Home",
|
|
// so we just assume here that the user is originating from the base route!!
|
|
$highlightHome = DashboardHome::DEFAULT_HOME;
|
|
}
|
|
|
|
$this->dashboard->load($highlightHome, $highlightPane, true);
|
|
|
|
$this->createTabs();
|
|
|
|
$activeHome = $this->dashboard->getActiveEntry();
|
|
// We can't grant access the user to the dashboard manager if there aren't any dashboards to manage
|
|
if (! $activeHome || (! $activeHome->hasEntries() && $this->dashboard->countEntries() === 1)) {
|
|
$this->redirectNow(Dashboard::BASE_ROUTE);
|
|
}
|
|
|
|
$this->dashboard->activate('dashboard_settings');
|
|
|
|
$this->addControl(new Link(
|
|
[new Icon('plus'), t('Add new Home')],
|
|
Url::fromPath(Dashboard::BASE_ROUTE . '/new-home'),
|
|
[
|
|
'class' => ['button-link', 'add-home'],
|
|
'data-icinga-modal' => true,
|
|
'data-no-icinga-ajax' => true
|
|
]
|
|
));
|
|
|
|
$this->content->getAttributes()->add('class', 'dashboard-manager');
|
|
$this->controls->getAttributes()->add('class', ['separated', 'dashboard-manager-controls']);
|
|
|
|
$this->addContent(new Settings($this->dashboard));
|
|
}
|
|
|
|
/**
|
|
* Create tab aggregation
|
|
*/
|
|
private function createTabs()
|
|
{
|
|
$tabs = $this->dashboard->getTabs();
|
|
$activeHome = $this->dashboard->getActiveEntry();
|
|
if ($activeHome
|
|
&& (
|
|
! $activeHome->isDefaultHome()
|
|
|| $activeHome->hasEntries()
|
|
|| $this->dashboard->countEntries() > 1
|
|
)
|
|
) {
|
|
$params = [];
|
|
if (! $activeHome->isDefaultHome()) {
|
|
$params['home'] = $activeHome->getName();
|
|
}
|
|
|
|
if (($activePane = $activeHome->getActiveEntry())) {
|
|
$params['pane'] = $activePane->getName();
|
|
}
|
|
|
|
$tabs->extend(new DashboardSettings($params));
|
|
}
|
|
|
|
return $tabs;
|
|
}
|
|
}
|