mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-09-21 08:57:40 +02:00
Do some code refactoring
This commit is contained in:
parent
c2b475585f
commit
cdd60f965b
@ -7,15 +7,19 @@ namespace Icinga\Controllers;
|
||||
use GuzzleHttp\Psr7\ServerRequest;
|
||||
use Icinga\Forms\Dashboard\DashletForm;
|
||||
use Icinga\Forms\Dashboard\HomePaneForm;
|
||||
use Icinga\Forms\Dashboard\NewHomePaneForm;
|
||||
use Icinga\Forms\Dashboard\RemoveDashletForm;
|
||||
use Icinga\Forms\Dashboard\RemoveHomePaneForm;
|
||||
use Icinga\Forms\Dashboard\WelcomeForm;
|
||||
use Icinga\Model\ModuleDashlet;
|
||||
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\Dashboard\Setup\SetupNewDashboard;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Widget\Tabextension\DashboardSettings;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Compat\CompatController;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\ActionLink;
|
||||
@ -40,7 +44,7 @@ class DashboardsController extends CompatController
|
||||
$this->createTabs();
|
||||
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
if (! $activeHome || ! $activeHome->hasPanes()) {
|
||||
if (! $activeHome || ! $activeHome->hasEntries()) {
|
||||
$this->getTabs()->add('dashboard', [
|
||||
'active' => true,
|
||||
'title' => t('Welcome'),
|
||||
@ -54,8 +58,6 @@ class DashboardsController extends CompatController
|
||||
})->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$this->dashboard->setWelcomeForm($welcomeForm);
|
||||
} elseif (empty($activeHome->getPanes(true))) {
|
||||
// TODO(TBD): What to do when the user has only disabled dashboards? Should we render the welcome screen?
|
||||
} elseif (($pane = $this->getParam('pane'))) {
|
||||
$this->getTabs()->activate($pane);
|
||||
}
|
||||
@ -71,38 +73,43 @@ class DashboardsController extends CompatController
|
||||
public function homeAction()
|
||||
{
|
||||
$home = $this->params->getRequired('home');
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
$this->createTabs();
|
||||
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
if (! $activeHome || empty($activeHome->getPanes(true))) {
|
||||
$this->getTabs()->add($home, [
|
||||
if (! $activeHome->getEntries()) {
|
||||
$this->getTabs()->add($activeHome->getName(), [
|
||||
'active' => true,
|
||||
'title' => $home,
|
||||
'title' => $activeHome->getTitle(),
|
||||
'url' => Url::fromRequest()
|
||||
]);
|
||||
|
||||
// Not to render the cog icon before the above tab
|
||||
$this->createTabs();
|
||||
} elseif (($pane = $this->getParam('pane'))) {
|
||||
$this->createTabs();
|
||||
|
||||
$this->dashboard->activate($pane);
|
||||
}
|
||||
|
||||
$this->content = $this->dashboard;
|
||||
}
|
||||
|
||||
public function renameHomeAction()
|
||||
public function editHomeAction()
|
||||
{
|
||||
$this->setTitle(t('Update Home'));
|
||||
|
||||
$home = $this->params->getRequired('home');
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
$homeForm = (new HomePaneForm($this->dashboard))
|
||||
->on(HomePaneForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})
|
||||
->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
@ -115,19 +122,41 @@ class DashboardsController extends CompatController
|
||||
$this->setTitle(t('Remove Home'));
|
||||
|
||||
$home = $this->params->getRequired('home');
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
$homeForm = (new RemoveHomePaneForm($this->dashboard))
|
||||
->on(RemoveHomePaneForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})
|
||||
->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$this->addContent($homeForm);
|
||||
}
|
||||
|
||||
public function newPaneAction()
|
||||
{
|
||||
$this->setTitle(t('Add new Dashboard'));
|
||||
|
||||
$home = $this->params->getRequired('home');
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
$paneForm = (new NewHomePaneForm($this->dashboard))
|
||||
->on(NewHomePaneForm::ON_SUCCESS, function () {
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})
|
||||
->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$this->addContent($paneForm);
|
||||
}
|
||||
|
||||
public function editPaneAction()
|
||||
{
|
||||
$this->setTitle(t('Update Pane'));
|
||||
@ -135,21 +164,23 @@ class DashboardsController extends CompatController
|
||||
$pane = $this->params->getRequired('pane');
|
||||
$home = $this->params->getRequired('home');
|
||||
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
if (! $this->dashboard->getActiveHome()->hasPane($pane)) {
|
||||
if (! $this->dashboard->getActiveHome()->hasEntry($pane)) {
|
||||
$this->httpNotFound(sprintf(t('Pane "%s" not found'), $pane));
|
||||
}
|
||||
|
||||
$paneForm = (new HomePaneForm($this->dashboard))
|
||||
->on(HomePaneForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})
|
||||
->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$paneForm->load($this->dashboard->getActiveHome()->getPane($pane));
|
||||
$paneForm->load($this->dashboard->getActiveHome()->getEntry($pane));
|
||||
|
||||
$this->addContent($paneForm);
|
||||
}
|
||||
@ -161,25 +192,21 @@ class DashboardsController extends CompatController
|
||||
$home = $this->params->getRequired('home');
|
||||
$paneParam = $this->params->getRequired('pane');
|
||||
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
if (! $this->dashboard->getActiveHome()->hasPane($paneParam)) {
|
||||
if (! $this->dashboard->getActiveHome()->hasEntry($paneParam)) {
|
||||
$this->httpNotFound(sprintf(t('Pane "%s" not found'), $paneParam));
|
||||
}
|
||||
|
||||
$paneForm = new RemoveHomePaneForm($this->dashboard);
|
||||
$paneForm->populate(['org_name' => $paneParam]);
|
||||
$paneForm->on(RemoveHomePaneForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
})->handleRequest(ServerRequest::fromGlobals());
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$paneForm->getElement('btn_remove')->setLabel(t('Remove Pane'));
|
||||
$paneForm->prependHtml(HtmlElement::create('h1', null, sprintf(
|
||||
t('Please confirm removal of dashboard pane "%s"'),
|
||||
$paneParam
|
||||
)));
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$this->addContent($paneForm);
|
||||
}
|
||||
@ -191,16 +218,11 @@ class DashboardsController extends CompatController
|
||||
$dashletForm = new DashletForm($this->dashboard);
|
||||
$dashletForm->populate($this->getRequest()->getPost());
|
||||
$dashletForm->on(DashletForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
$params = $this->getAllParams();
|
||||
if ($this->getParam('url')) {
|
||||
$params['url'] = rawurldecode($this->getParam('url'));
|
||||
}
|
||||
|
||||
$dashletForm->populate($params);
|
||||
|
||||
$this->addContent($dashletForm);
|
||||
}
|
||||
|
||||
@ -209,11 +231,13 @@ class DashboardsController extends CompatController
|
||||
$this->setTitle(t('Edit Dashlet'));
|
||||
|
||||
$pane = $this->validateDashletParams();
|
||||
$dashlet = $pane->getDashlet($this->getParam('dashlet'));
|
||||
$dashlet = $pane->getEntry($this->getParam('dashlet'));
|
||||
|
||||
$dashletForm = (new DashletForm($this->dashboard))
|
||||
->on(DashletForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})
|
||||
->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
@ -225,12 +249,14 @@ class DashboardsController extends CompatController
|
||||
|
||||
public function removeDashletAction()
|
||||
{
|
||||
$this->validateDashletParams();
|
||||
$this->setTitle(t('Remove Dashlet'));
|
||||
$this->validateDashletParams();
|
||||
|
||||
$removeForm = (new RemoveDashletForm($this->dashboard))
|
||||
->on(RemoveDashletForm::ON_SUCCESS, function () {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
$this->getResponse()->setAutoRefreshInterval(1);
|
||||
|
||||
$this->redirectNow(Url::fromPath(Dashboard::BASE_ROUTE . '/settings'));
|
||||
})
|
||||
->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
@ -243,60 +269,109 @@ class DashboardsController extends CompatController
|
||||
public function reorderWidgetsAction()
|
||||
{
|
||||
$this->assertHttpMethod('post');
|
||||
if (! $this->getRequest()->isApiRequest()) {
|
||||
$this->httpBadRequest('No API request');
|
||||
}
|
||||
|
||||
if (! preg_match('/([^;]*);?/', $this->getRequest()->getHeader('Content-Type'), $matches)
|
||||
|| $matches[1] !== 'application/json') {
|
||||
$this->httpBadRequest('No JSON content');
|
||||
}
|
||||
|
||||
$dashboards = $this->getRequest()->getPost();
|
||||
$widgetType = array_pop($dashboards);
|
||||
if (! isset($dashboards['dashboardData'])) {
|
||||
$this->httpBadRequest(t('Invalid request data'));
|
||||
}
|
||||
|
||||
foreach ($dashboards as $key => $panes) {
|
||||
$home = $widgetType === 'Homes' ? $panes : $key;
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
$this->httpNotFound(sprintf(t('Dashboard home "%s" not found'), $home));
|
||||
$dashboards = Json::decode($dashboards['dashboardData'], true);
|
||||
$originals = $dashboards['originals'];
|
||||
unset($dashboards['Type']);
|
||||
unset($dashboards['originals']);
|
||||
|
||||
$orgHome = null;
|
||||
$orgPane = null;
|
||||
if ($originals && isset($originals['originalHome'])) {
|
||||
/** @var DashboardHome $orgHome */
|
||||
$orgHome = $this->dashboard->getEntry($originals['originalHome']);
|
||||
$orgHome->setActive()->loadDashboardEntries();
|
||||
|
||||
if (isset($originals['originalPane'])) {
|
||||
$orgPane = $orgHome->getEntry($originals['originalPane']);
|
||||
$orgHome->setEntries([$orgPane->getName() => $orgPane]);
|
||||
}
|
||||
}
|
||||
|
||||
$reroutePath = $dashboards['redirectPath'];
|
||||
unset($dashboards['redirectPath']);
|
||||
|
||||
foreach ($dashboards as $home => $value) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
Notification::error(sprintf(t('Dashboard home "%s" not found'), $home));
|
||||
break;
|
||||
}
|
||||
|
||||
$home = $this->dashboard->getHome($home);
|
||||
if ($widgetType === 'Homes') {
|
||||
$home->setPriority($key);
|
||||
$this->dashboard->manageHome($home);
|
||||
/** @var DashboardHome $home */
|
||||
$home = $this->dashboard->getEntry($home);
|
||||
if (! is_array($value)) {
|
||||
$this->dashboard->reorderWidget($home, (int) $value);
|
||||
|
||||
continue;
|
||||
Notification::success(sprintf(t('Updated dashboard home "%s" successfully'), $home->getTitle()));
|
||||
break;
|
||||
}
|
||||
|
||||
$home->setActive();
|
||||
$home->loadPanesFromDB();
|
||||
|
||||
foreach ($panes as $innerKey => $value) {
|
||||
$pane = $widgetType === 'Dashboards' ? $value : $innerKey;
|
||||
if (! $home->hasPane($pane)) {
|
||||
$this->httpNotFound(sprintf(t('Dashboard pane "%s" not found'), $pane));
|
||||
$home->setActive()->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->getPane($pane);
|
||||
if ($widgetType === 'Dashboards') {
|
||||
$pane->setPriority($innerKey);
|
||||
$home->managePanes($pane);
|
||||
} else {
|
||||
foreach ($value as $order => $dashlet) {
|
||||
if (! $pane->hasDashlet($dashlet)) {
|
||||
$this->httpNotFound(sprintf(t('Dashlet "%s" not found'), $dashlet));
|
||||
}
|
||||
|
||||
$dashlet = $pane->getDashlet($dashlet);
|
||||
$dashlet->setPriority($order);
|
||||
$pane->manageDashlets($dashlet);
|
||||
/** @var Pane $pane */
|
||||
$pane = $home->hasEntry($pane) ? $home->getEntry($pane) : $orgHome->getEntry($pane);
|
||||
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()
|
||||
));
|
||||
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());
|
||||
}
|
||||
|
||||
Notification::success(sprintf(
|
||||
t('%s dashboard 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('Dashlet "%s" already exists within "%s" dashboard pane'),
|
||||
$dashlet,
|
||||
$pane->getTitle()
|
||||
));
|
||||
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()
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exit;
|
||||
$this->redirectNow($reroutePath);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -320,10 +395,6 @@ class DashboardsController extends CompatController
|
||||
$setupForm = new SetupNewDashboard($this->dashboard);
|
||||
$setupForm->initDashlets(Dashboard::getModuleDashlets($query));
|
||||
$setupForm->on(SetupNewDashboard::ON_SUCCESS, function () use ($setupForm) {
|
||||
if ($setupForm->getPopulatedValue('btn_cancel')) {
|
||||
$this->redirectNow('__CLOSE__');
|
||||
}
|
||||
|
||||
$this->redirectNow($setupForm->getRedirectUrl());
|
||||
})->handleRequest(ServerRequest::fromGlobals());
|
||||
|
||||
@ -333,8 +404,12 @@ class DashboardsController extends CompatController
|
||||
public function settingsAction()
|
||||
{
|
||||
$this->createTabs();
|
||||
// TODO(yh): This may raise an exception when the given tab name doesn't exist.
|
||||
// But as ipl::Tabs() doesn't offer the possibility to check this beforehand, just ignore it for now!!
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
// We can't grant access the user to the dashboard manager if there aren't any dashboards to manage
|
||||
if (! $activeHome || (! $activeHome->hasEntries() && count($this->dashboard->getEntries()) === 1)) {
|
||||
$this->redirectNow(Dashboard::BASE_ROUTE);
|
||||
}
|
||||
|
||||
$this->dashboard->activate('dashboard_settings');
|
||||
|
||||
$this->addControl(new ActionLink(
|
||||
@ -358,7 +433,7 @@ class DashboardsController extends CompatController
|
||||
{
|
||||
$tabs = $this->dashboard->getTabs();
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
if ($activeHome && $activeHome->hasPanes()) {
|
||||
if (($activeHome && $activeHome->hasEntries()) || count($this->dashboard->getEntries()) > 1) {
|
||||
$tabs->extend(new DashboardSettings());
|
||||
}
|
||||
|
||||
@ -371,16 +446,16 @@ class DashboardsController extends CompatController
|
||||
$pane = $this->params->getRequired('pane');
|
||||
$dashlet = $this->params->getRequired('dashlet');
|
||||
|
||||
if (! $this->dashboard->hasHome($home)) {
|
||||
if (! $this->dashboard->hasEntry($home)) {
|
||||
$this->httpNotFound(sprintf(t('Home "%s" not found'), $home));
|
||||
}
|
||||
|
||||
if (! $this->dashboard->getActiveHome()->hasPane($pane)) {
|
||||
if (! $this->dashboard->getActiveHome()->hasEntry($pane)) {
|
||||
$this->httpNotFound(sprintf(t('Pane "%s" not found'), $pane));
|
||||
}
|
||||
|
||||
$pane = $this->dashboard->getActiveHome()->getPane($pane);
|
||||
if (! $pane->hasDashlet($dashlet)) {
|
||||
$pane = $this->dashboard->getActiveHome()->getEntry($pane);
|
||||
if (! $pane->hasEntry($dashlet)) {
|
||||
$this->httpNotFound(sprintf(t('Dashlet "%s" not found'), $dashlet));
|
||||
}
|
||||
|
||||
|
113
application/forms/Dashboard/BaseDashboardForm.php
Normal file
113
application/forms/Dashboard/BaseDashboardForm.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Icinga\Web\Dashboard\Common\BaseDashboard;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use ipl\Html\Contract\FormElement;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\Icon;
|
||||
|
||||
/**
|
||||
* Base Form for all kinds of dashboard types
|
||||
*/
|
||||
abstract class BaseDashboardForm extends CompatForm
|
||||
{
|
||||
const CREATE_NEW_HOME = 'Create new Home';
|
||||
|
||||
const CREATE_NEW_PANE = 'Create new Dashboard';
|
||||
|
||||
/**
|
||||
* Dashboard instance for which this form is being rendered
|
||||
*
|
||||
* @var Dashboard
|
||||
*/
|
||||
protected $dashboard;
|
||||
|
||||
/**
|
||||
* Create a new Dashboard Form
|
||||
*
|
||||
* @param Dashboard $dashboard
|
||||
*/
|
||||
public function __construct(Dashboard $dashboard)
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
|
||||
// This is needed for the modal views
|
||||
$this->setAction((string) Url::fromRequest());
|
||||
}
|
||||
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
// We don't use addElement() for the form controls, so the form has no way of knowing
|
||||
// that we do have a submit button and will always be submitted with autosubmit elements
|
||||
return $this->hasBeenSent() && $this->getPopulatedValue('submit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate form data from config
|
||||
*
|
||||
* @param BaseDashboard $dashboard
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function load(BaseDashboard $dashboard)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Create custom form controls
|
||||
*
|
||||
* @return HtmlElement
|
||||
*/
|
||||
protected function createFormControls()
|
||||
{
|
||||
return HtmlElement::create('div', ['class' => 'control-group form-controls']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a cancel button
|
||||
*
|
||||
* @return FormElement
|
||||
*/
|
||||
protected function createCancelButton()
|
||||
{
|
||||
return $this->createElement('submitButton', 'btn_cancel', ['class' => 'modal-cancel', 'label' => t('Cancel')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a remove button
|
||||
*
|
||||
* @param Url $action
|
||||
* @param string $label
|
||||
*
|
||||
* @return FormElement
|
||||
*/
|
||||
protected function createRemoveButton(Url $action, $label)
|
||||
{
|
||||
return $this->createElement('submitButton', 'btn_remove', [
|
||||
'class' => 'remove-button',
|
||||
'label' => [new Icon('trash'), $label],
|
||||
'formaction' => (string) $action
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and register a submit button
|
||||
*
|
||||
* @param string $label
|
||||
*
|
||||
* @return FormElement
|
||||
*/
|
||||
protected function registerSubmitButton($label)
|
||||
{
|
||||
$submitElement = $this->createElement('submit', 'submit', ['class' => 'btn-primary', 'label' => $label]);
|
||||
$this->registerElement($submitElement);
|
||||
|
||||
return $submitElement;
|
||||
}
|
||||
}
|
@ -6,136 +6,93 @@ namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Exception;
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\Dashboard\Common\BaseDashboard;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Dashboard\Dashlet;
|
||||
use Icinga\Web\Dashboard\Pane;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
|
||||
/**
|
||||
* Form to add an url a dashboard pane
|
||||
*/
|
||||
class DashletForm extends CompatForm
|
||||
class DashletForm extends BaseDashboardForm
|
||||
{
|
||||
/**
|
||||
* @var Dashboard
|
||||
*/
|
||||
private $dashboard;
|
||||
|
||||
public function __construct(Dashboard $dashboard)
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
|
||||
$this->setAction((string) Url::fromRequest());
|
||||
}
|
||||
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
return $this->hasBeenSent() && $this->getPopulatedValue('submit');
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$requestUrl = Url::fromRequest();
|
||||
|
||||
$homes = $this->dashboard->getHomeKeyTitleArr();
|
||||
$homes = $this->dashboard->getEntryKeyTitleArr();
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
$currentHome = $requestUrl->getParam('home', reset($homes));
|
||||
$populatedHome = $this->getPopulatedValue('home', $currentHome);
|
||||
|
||||
$panes = [];
|
||||
if ($currentHome === $populatedHome && $this->getPopulatedValue('create_new_home') !== 'y') {
|
||||
if ($currentHome === $populatedHome && $populatedHome !== self::CREATE_NEW_HOME) {
|
||||
if (! $currentHome || ! $activeHome) {
|
||||
// Home param isn't passed through, so let's try to load based on the first home
|
||||
$firstHome = $this->dashboard->rewindHomes();
|
||||
$firstHome = $this->dashboard->rewindEntries();
|
||||
if ($firstHome) {
|
||||
$this->dashboard->loadDashboards($firstHome->getName());
|
||||
$this->dashboard->loadDashboardEntries($firstHome->getName());
|
||||
|
||||
$panes = $firstHome->getPaneKeyTitleArr();
|
||||
$panes = $firstHome->getEntryKeyTitleArr();
|
||||
}
|
||||
} else {
|
||||
$panes = $activeHome->getPaneKeyTitleArr();
|
||||
$panes = $activeHome->getEntryKeyTitleArr();
|
||||
}
|
||||
} elseif ($this->dashboard->hasHome($populatedHome)) {
|
||||
$this->dashboard->loadDashboards($populatedHome);
|
||||
} elseif ($this->dashboard->hasEntry($populatedHome)) {
|
||||
$this->dashboard->loadDashboardEntries($populatedHome);
|
||||
|
||||
$panes = $this->dashboard->getActiveHome()->getPaneKeyTitleArr();
|
||||
$panes = $this->dashboard->getActiveHome()->getEntryKeyTitleArr();
|
||||
}
|
||||
|
||||
$this->addElement('hidden', 'org_pane', ['required' => false]);
|
||||
$this->addElement('hidden', 'org_home', ['required' => false]);
|
||||
$this->addElement('hidden', 'org_dashlet', ['required' => false]);
|
||||
|
||||
$this->addElement('checkbox', 'create_new_home', [
|
||||
'class' => 'autosubmit',
|
||||
'required' => false,
|
||||
'disabled' => empty($homes) ?: null,
|
||||
'label' => t('New Dashboard Home'),
|
||||
'description' => t('Check this box if you want to add the dashboard to a new dashboard home.'),
|
||||
$this->addElement('select', 'home', [
|
||||
'class' => 'autosubmit',
|
||||
'required' => true,
|
||||
'disabled' => empty($homes) ?: null,
|
||||
'value' => $populatedHome,
|
||||
'multiOptions' => array_merge([self::CREATE_NEW_HOME => self::CREATE_NEW_HOME], $homes),
|
||||
'label' => t('Select Home'),
|
||||
'descriptions' => t('Select a dashboard home you want to add the dashboard pane to.')
|
||||
]);
|
||||
|
||||
if (empty($homes) || $this->getPopulatedValue('create_new_home') === 'y') {
|
||||
// $el->attrs->set() has no effect here anymore, so we need to register a proper callback
|
||||
$this->getElement('create_new_home')
|
||||
->getAttributes()
|
||||
->registerAttributeCallback('checked', function () {
|
||||
return true;
|
||||
});
|
||||
|
||||
$this->addElement('text', 'home', [
|
||||
if (empty($homes) || $populatedHome === self::CREATE_NEW_HOME) {
|
||||
$this->addElement('text', 'new_home', [
|
||||
'required' => true,
|
||||
'label' => t('Dashboard Home'),
|
||||
'label' => t('Home Title'),
|
||||
'placeholder' => t('Enter dashboard home title'),
|
||||
'description' => t('Enter a title for the new dashboard home.')
|
||||
]);
|
||||
} else {
|
||||
$this->addElement('select', 'home', [
|
||||
'required' => true,
|
||||
'class' => 'autosubmit',
|
||||
'value' => $currentHome,
|
||||
'multiOptions' => $homes,
|
||||
'label' => t('Dashboard Home'),
|
||||
'descriptions' => t('Select a home you want to add the dashboard pane to.')
|
||||
]);
|
||||
}
|
||||
|
||||
$disable = empty($panes) || $this->getPopulatedValue('create_new_home') === 'y';
|
||||
$this->addElement('checkbox', 'create_new_pane', [
|
||||
'required' => false,
|
||||
'class' => 'autosubmit',
|
||||
'disabled' => $disable ?: null,
|
||||
'label' => t('New Dashboard'),
|
||||
'description' => t('Check this box if you want to add the dashlet to a new dashboard.'),
|
||||
]);
|
||||
|
||||
$populatedPane = $this->getPopulatedValue('pane');
|
||||
// Pane element's values are depending on the home element's value
|
||||
if (! in_array($this->getPopulatedValue('pane'), $panes)) {
|
||||
if ($populatedPane !== self::CREATE_NEW_PANE && ! in_array($populatedPane, $panes)) {
|
||||
$this->clearPopulatedValue('pane');
|
||||
}
|
||||
|
||||
if ($disable || $this->getValue('create_new_pane') === 'y') {
|
||||
// $el->attrs->set() has no effect here anymore, so we need to register a proper callback
|
||||
$this->getElement('create_new_pane')
|
||||
->getAttributes()
|
||||
->registerAttributeCallback('checked', function () {
|
||||
return true;
|
||||
});
|
||||
$populatedPane = $this->getPopulatedValue('pane', reset($panes));
|
||||
$disable = empty($panes) || $populatedHome === self::CREATE_NEW_HOME;
|
||||
$this->addElement('select', 'pane', [
|
||||
'class' => 'autosubmit',
|
||||
'required' => true,
|
||||
'disabled' => $disable ?: null,
|
||||
'value' => ! $disable ? $populatedPane : self::CREATE_NEW_PANE, // Cheat the browser complains
|
||||
'multiOptions' => array_merge([self::CREATE_NEW_PANE => self::CREATE_NEW_PANE], $panes),
|
||||
'label' => t('Select Dashboard'),
|
||||
'description' => t('Select a dashboard you want to add the dashlet to.'),
|
||||
]);
|
||||
|
||||
$this->addElement('text', 'pane', [
|
||||
if ($disable || $this->getPopulatedValue('pane') === self::CREATE_NEW_PANE) {
|
||||
$this->addElement('text', 'new_pane', [
|
||||
'required' => true,
|
||||
'label' => t('New Dashboard Title'),
|
||||
'label' => t('Dashboard Title'),
|
||||
'placeholder' => t('Enter dashboard title'),
|
||||
'description' => t('Enter a title for the new dashboard.'),
|
||||
]);
|
||||
} else {
|
||||
$this->addElement('select', 'pane', [
|
||||
'required' => true,
|
||||
'value' => reset($panes),
|
||||
'multiOptions' => $panes,
|
||||
'label' => t('Dashboard'),
|
||||
'description' => t('Select a dashboard you want to add the dashlet to.'),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->addHtml(new HtmlElement('hr'));
|
||||
@ -143,6 +100,7 @@ class DashletForm extends CompatForm
|
||||
$this->addElement('textarea', 'url', [
|
||||
'required' => true,
|
||||
'label' => t('Url'),
|
||||
'placeholder' => t('Enter dashlet url'),
|
||||
'description' => t(
|
||||
'Enter url to be loaded in the dashlet. You can paste the full URL, including filters.'
|
||||
),
|
||||
@ -151,40 +109,24 @@ class DashletForm extends CompatForm
|
||||
$this->addElement('text', 'dashlet', [
|
||||
'required' => true,
|
||||
'label' => t('Dashlet Title'),
|
||||
'placeholder' => t('Enter a dashlet title'),
|
||||
'description' => t('Enter a title for the dashlet.'),
|
||||
]);
|
||||
|
||||
$url = (string) Url::fromPath(Dashboard::BASE_ROUTE . '/browse');
|
||||
$removeButton = null;
|
||||
if ($requestUrl->getPath() === Dashboard::BASE_ROUTE . '/edit-dashlet') {
|
||||
$targetUrl = (clone $requestUrl)->setPath(Dashboard::BASE_ROUTE . '/remove-dashlet');
|
||||
$removeButton = $this->createRemoveButton($targetUrl, t('Remove Dashlet'));
|
||||
}
|
||||
|
||||
$element = $this->createElement('submit', 'submit', ['label' => t('Add to Dashboard')]);
|
||||
$this->registerElement($element)->decorate($element);
|
||||
|
||||
// We might need this later to allow the user to browse dashlets when creating a dashlet
|
||||
$this->addElement('submit', 'btn_browse', [
|
||||
'label' => t('Browse Dashlets'),
|
||||
'href' => $url,
|
||||
'formaction' => $url,
|
||||
$formControls = $this->createFormControls();
|
||||
$formControls->add([
|
||||
$this->registerSubmitButton(t('Add to Dashboard')),
|
||||
$removeButton,
|
||||
$this->createCancelButton()
|
||||
]);
|
||||
|
||||
$this->getElement('btn_browse')->setWrapper($element->getWrapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate form data from config
|
||||
*
|
||||
* @param Dashlet $dashlet
|
||||
*/
|
||||
public function load(Dashlet $dashlet)
|
||||
{
|
||||
$home = Url::fromRequest()->getParam('home');
|
||||
$this->populate(array(
|
||||
'org_home' => $home,
|
||||
'org_pane' => $dashlet->getPane()->getName(),
|
||||
'pane' => $dashlet->getPane()->getTitle(),
|
||||
'org_dashlet' => $dashlet->getName(),
|
||||
'dashlet' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()->getRelativeUrl()
|
||||
));
|
||||
$this->addHtml($formControls);
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
@ -192,27 +134,38 @@ class DashletForm extends CompatForm
|
||||
$conn = Dashboard::getConn();
|
||||
$dashboard = $this->dashboard;
|
||||
|
||||
$selectedHome = $this->getPopulatedValue('home');
|
||||
if (! $selectedHome || $selectedHome === self::CREATE_NEW_HOME) {
|
||||
$selectedHome = $this->getPopulatedValue('new_home');
|
||||
}
|
||||
|
||||
$selectedPane = $this->getPopulatedValue('pane');
|
||||
// If "pane" element is disabled, there will be no populated value for it
|
||||
if (! $selectedPane || $selectedPane === self::CREATE_NEW_PANE) {
|
||||
$selectedPane = $this->getPopulatedValue('new_pane');
|
||||
}
|
||||
|
||||
if (Url::fromRequest()->getPath() === Dashboard::BASE_ROUTE . '/new-dashlet') {
|
||||
$home = new DashboardHome($this->getValue('home'));
|
||||
if ($dashboard->hasHome($home->getName())) {
|
||||
$home = $dashboard->getHome($home->getName());
|
||||
if ($home->getName() !== $dashboard->getActiveHome()->getName()) {
|
||||
$home->setActive();
|
||||
$home->loadPanesFromDB();
|
||||
$currentHome = new DashboardHome($selectedHome);
|
||||
if ($dashboard->hasEntry($currentHome->getName())) {
|
||||
$currentHome = clone $dashboard->getEntry($currentHome->getName());
|
||||
if ($currentHome->getName() !== $dashboard->getActiveHome()->getName()) {
|
||||
$currentHome->setActive();
|
||||
$currentHome->loadDashboardEntries();
|
||||
}
|
||||
}
|
||||
|
||||
$pane = new Pane($this->getValue('pane'));
|
||||
if ($home->hasPane($pane->getName())) {
|
||||
$pane = $home->getPane($pane->getName());
|
||||
$currentPane = new Pane($selectedPane);
|
||||
if ($currentHome->hasEntry($currentPane->getName())) {
|
||||
$currentPane = clone $currentHome->getEntry($currentPane->getName());
|
||||
}
|
||||
|
||||
$dashlet = new Dashlet($this->getValue('dashlet'), $this->getValue('url'), $pane);
|
||||
if ($pane->hasDashlet($dashlet->getName())) {
|
||||
$dashlet = new Dashlet($this->getValue('dashlet'), $this->getValue('url'), $currentPane);
|
||||
if ($currentPane->hasEntry($dashlet->getName())) {
|
||||
Notification::error(sprintf(
|
||||
t('Dashlet "%s" already exists within the "%s" dashboard pane'),
|
||||
$dashlet->getTitle(),
|
||||
$pane->getTitle()
|
||||
$currentPane->getTitle()
|
||||
));
|
||||
|
||||
return;
|
||||
@ -221,12 +174,12 @@ class DashletForm extends CompatForm
|
||||
$conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$dashboard->manageHome($home);
|
||||
$home->managePanes($pane);
|
||||
$pane->manageDashlets($dashlet);
|
||||
$dashboard->manageEntry($currentHome);
|
||||
$currentHome->manageEntry($currentPane);
|
||||
$currentPane->manageEntry($dashlet);
|
||||
|
||||
$conn->commitTransaction();
|
||||
} catch (Exception $err) { // This error handling is just for debugging purpose! Will be removed!
|
||||
} catch (Exception $err) {
|
||||
Logger::error($err);
|
||||
$conn->rollBackTransaction();
|
||||
|
||||
@ -235,26 +188,35 @@ class DashletForm extends CompatForm
|
||||
|
||||
Notification::success(sprintf(t('Created dashlet "%s" successfully'), $dashlet->getTitle()));
|
||||
} else {
|
||||
$orgHome = $dashboard->getHome($this->getValue('org_home'));
|
||||
$orgPane = $orgHome->getPane($this->getValue('org_pane'));
|
||||
$orgDashlet = $orgPane->getDashlet($this->getValue('org_dashlet'));
|
||||
$orgHome = $dashboard->getEntry($this->getValue('org_home'));
|
||||
$orgPane = $orgHome->getEntry($this->getValue('org_pane'));
|
||||
$orgDashlet = $orgPane->getEntry($this->getValue('org_dashlet'));
|
||||
|
||||
$currentHome = new DashboardHome($this->getValue('home'));
|
||||
if ($dashboard->hasHome($currentHome->getName())) {
|
||||
$currentHome = $dashboard->getHome($currentHome->getName());
|
||||
$currentHome = new DashboardHome($selectedHome);
|
||||
if ($dashboard->hasEntry($currentHome->getName())) {
|
||||
$currentHome = clone $dashboard->getEntry($currentHome->getName());
|
||||
$activeHome = $dashboard->getActiveHome();
|
||||
if ($currentHome->getName() !== $activeHome->getName()) {
|
||||
$currentHome->setActive();
|
||||
$currentHome->loadPanesFromDB();
|
||||
$currentHome->loadDashboardEntries();
|
||||
}
|
||||
}
|
||||
|
||||
$currentPane = new Pane($this->getValue('pane'));
|
||||
if ($currentHome->hasPane($currentPane->getName())) {
|
||||
$currentPane = $currentHome->getPane($currentPane->getName());
|
||||
$currentPane = new Pane($selectedPane);
|
||||
if ($currentHome->hasEntry($currentPane->getName())) {
|
||||
$currentPane = clone $currentHome->getEntry($currentPane->getName());
|
||||
}
|
||||
|
||||
$currentPane->setHome($currentHome);
|
||||
// When the user wishes to create a new dashboard pane, we have to explicitly reset the dashboard panes
|
||||
// of the original home, so that it isn't considered as we want to move the pane even though it isn't
|
||||
// supposed to when the original home contains a dashboard with the same name
|
||||
// @see DashboardHome::managePanes() for details
|
||||
$selectedPane = $this->getPopulatedValue('pane');
|
||||
if ((! $selectedPane || $selectedPane === self::CREATE_NEW_PANE)
|
||||
&& ! $currentHome->hasEntry($currentPane->getName())) {
|
||||
$orgHome->setEntries([]);
|
||||
}
|
||||
|
||||
$currentDashlet = clone $orgDashlet;
|
||||
$currentDashlet
|
||||
@ -263,7 +225,7 @@ class DashletForm extends CompatForm
|
||||
->setTitle($this->getValue('dashlet'));
|
||||
|
||||
if ($orgPane->getName() !== $currentPane->getName()
|
||||
&& $currentPane->hasDashlet($currentDashlet->getName())) {
|
||||
&& $currentPane->hasEntry($currentDashlet->getName())) {
|
||||
Notification::error(sprintf(
|
||||
t('Failed to move dashlet "%s": Dashlet already exists within the "%s" dashboard pane'),
|
||||
$currentDashlet->getTitle(),
|
||||
@ -287,12 +249,18 @@ class DashletForm extends CompatForm
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($paneDiff)) {
|
||||
// No dashboard diff means the dashlet is still in the same pane, so just
|
||||
// reset the dashlets of the original pane
|
||||
$orgPane->setEntries([]);
|
||||
}
|
||||
|
||||
$conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$dashboard->manageHome($currentHome);
|
||||
$currentHome->managePanes($currentPane, $orgHome);
|
||||
$currentPane->manageDashlets($currentDashlet, $orgPane);
|
||||
$dashboard->manageEntry($currentHome);
|
||||
$currentHome->manageEntry($currentPane, $orgHome);
|
||||
$currentPane->manageEntry($currentDashlet, $orgPane);
|
||||
|
||||
$conn->commitTransaction();
|
||||
} catch (Exception $err) {
|
||||
@ -305,4 +273,21 @@ class DashletForm extends CompatForm
|
||||
Notification::success(sprintf(t('Updated dashlet "%s" successfully'), $currentDashlet->getTitle()));
|
||||
}
|
||||
}
|
||||
|
||||
public function load(BaseDashboard $dashlet)
|
||||
{
|
||||
$home = Url::fromRequest()->getParam('home');
|
||||
/** @var Dashlet $dashlet */
|
||||
$this->populate(array(
|
||||
'org_home' => $home,
|
||||
'org_pane' => $dashlet->getPane()->getName(),
|
||||
'org_dashlet' => $dashlet->getName(),
|
||||
'dashlet' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()->getRelativeUrl()
|
||||
));
|
||||
|
||||
if ($this->getPopulatedValue('pane') !== self::CREATE_NEW_PANE) {
|
||||
$this->populate(['pane' => $dashlet->getPane()->getTitle()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,81 +5,53 @@
|
||||
namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Icinga\Application\Logger;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\Common\BaseDashboard;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Dashboard\Pane;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class HomePaneForm extends CompatForm
|
||||
class HomePaneForm extends BaseDashboardForm
|
||||
{
|
||||
/** @var Dashboard */
|
||||
protected $dashboard;
|
||||
|
||||
public function __construct(Dashboard $dashboard)
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
|
||||
// We need to set this explicitly needed for modals
|
||||
$this->setAction((string) Url::fromRequest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate form data from config
|
||||
*
|
||||
* @param DashboardHome|Pane $widget
|
||||
*/
|
||||
public function load($widget)
|
||||
{
|
||||
$title = $widget instanceof Pane ? $widget->getTitle() : $widget->getLabel();
|
||||
$this->populate([
|
||||
'org_title' => $title,
|
||||
'title' => $title,
|
||||
'org_name' => $widget->getName()
|
||||
]);
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$titleDesc = t('Edit the title of this dashboard home');
|
||||
$buttonLabel = t('Update Home');
|
||||
$removeButtonLabel = t('Remove Home');
|
||||
|
||||
$requestUrl = Url::fromRequest();
|
||||
$removeTargetUrl = (clone $requestUrl)->setPath(Dashboard::BASE_ROUTE . '/remove-home');
|
||||
|
||||
$this->addElement('hidden', 'org_name', ['required' => false]);
|
||||
$this->addElement('hidden', 'org_title', ['required' => false]);
|
||||
|
||||
$titleDesc = t('Edit the title of this dashboard home');
|
||||
$buttonLabel = t('Update Home');
|
||||
if (Url::fromRequest()->getPath() === Dashboard::BASE_ROUTE . '/edit-pane') {
|
||||
if ($requestUrl->getPath() === Dashboard::BASE_ROUTE . '/edit-pane') {
|
||||
$titleDesc = t('Edit the title of this dashboard pane');
|
||||
$buttonLabel = t('Update Pane');
|
||||
$removeButtonLabel = t('Remove Pane');
|
||||
|
||||
$homes = $this->dashboard->getHomeKeyTitleArr();
|
||||
$this->addElement('checkbox', 'create_new_home', [
|
||||
'required' => false,
|
||||
'class' => 'autosubmit',
|
||||
'disabled' => empty($homes) ?: null,
|
||||
'label' => t('New Dashboard Home'),
|
||||
'description' => t('Check this box if you want to move the pane to a new dashboard home.'),
|
||||
]);
|
||||
$removeTargetUrl = (clone $requestUrl)->setPath(Dashboard::BASE_ROUTE . '/remove-pane');
|
||||
|
||||
$homes = $this->dashboard->getEntryKeyTitleArr();
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
$populatedHome = $this->getPopulatedValue('home', $activeHome->getName());
|
||||
|
||||
if (empty($homes) || $this->getPopulatedValue('create_new_home') === 'y') {
|
||||
$this->getElement('create_new_home')->addAttributes(['checked' => 'checked']);
|
||||
$this->addElement('select', 'home', [
|
||||
'class' => 'autosubmit',
|
||||
'required' => true,
|
||||
'value' => $populatedHome,
|
||||
'multiOptions' => array_merge([self::CREATE_NEW_HOME => self::CREATE_NEW_HOME], $homes),
|
||||
'label' => t('Assign to Home'),
|
||||
'description' => t('Select a dashboard home you want to move the dashboard to.'),
|
||||
]);
|
||||
|
||||
$this->addElement('text', 'home', [
|
||||
if (empty($homes) || $this->getPopulatedValue('home') === self::CREATE_NEW_HOME) {
|
||||
$this->addElement('text', 'new_home', [
|
||||
'required' => true,
|
||||
'label' => t('Dashboard Home'),
|
||||
'placeholder' => t('Enter dashboard home title'),
|
||||
'description' => t('Enter a title for the new dashboard home.'),
|
||||
]);
|
||||
} else {
|
||||
$this->addElement('select', 'home', [
|
||||
'required' => true,
|
||||
'class' => 'autosubmit',
|
||||
'value' => $populatedHome,
|
||||
'multiOptions' => $homes,
|
||||
'label' => t('Move to Home'),
|
||||
'description' => t('Select a dashboard home you want to move the dashboard to.'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -89,46 +61,64 @@ class HomePaneForm extends CompatForm
|
||||
'description' => $titleDesc
|
||||
]);
|
||||
|
||||
$this->addElement('submit', 'btn_update', ['label' => $buttonLabel]);
|
||||
$formControls = $this->createFormControls();
|
||||
$formControls->add([
|
||||
$this->registerSubmitButton($buttonLabel),
|
||||
$this->createRemoveButton($removeTargetUrl, $removeButtonLabel),
|
||||
$this->createCancelButton()
|
||||
]);
|
||||
|
||||
$this->addHtml($formControls);
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
{
|
||||
$requestUrl = Url::fromRequest();
|
||||
if ($requestUrl->getPath() === Dashboard::BASE_ROUTE . '/edit-pane') {
|
||||
$orgHome = $this->dashboard->getHome($requestUrl->getParam('home'));
|
||||
$orgHome = $this->dashboard->getEntry($requestUrl->getParam('home'));
|
||||
|
||||
$currentHome = new DashboardHome($this->getValue('home'));
|
||||
if ($this->dashboard->hasHome($currentHome->getName())) {
|
||||
$currentHome = $this->dashboard->getHome($currentHome->getName());
|
||||
$selectedHome = $this->getPopulatedValue('home');
|
||||
if (! $selectedHome || $selectedHome === self::CREATE_NEW_HOME) {
|
||||
$selectedHome = $this->getPopulatedValue('new_home');
|
||||
}
|
||||
|
||||
$currentHome = new DashboardHome($selectedHome);
|
||||
if ($this->dashboard->hasEntry($currentHome->getName())) {
|
||||
/** @var DashboardHome $currentHome */
|
||||
$currentHome = clone $this->dashboard->getEntry($currentHome->getName());
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
if ($currentHome->getName() !== $activeHome->getName()) {
|
||||
$currentHome->setActive();
|
||||
$currentHome->loadPanesFromDB();
|
||||
$currentHome->setActive()->loadDashboardEntries();
|
||||
}
|
||||
}
|
||||
|
||||
$currentPane = $orgHome->getPane($this->getValue('org_name'));
|
||||
$currentPane = clone $orgHome->getEntry($this->getValue('org_name'));
|
||||
$currentPane
|
||||
->setHome($currentHome)
|
||||
->setTitle($this->getValue('title'));
|
||||
|
||||
if ($orgHome->getName() !== $currentHome->getName() && $currentHome->hasPane($currentPane->getName())) {
|
||||
if ($orgHome->getName() !== $currentHome->getName() && $currentHome->hasEntry($currentPane->getName())) {
|
||||
Notification::error(sprintf(
|
||||
t('Failed to move dashboard "%s": Dashbaord pane already exists within the "%s" dashboard home'),
|
||||
$currentPane->getTitle(),
|
||||
$currentHome->getLabel()
|
||||
$currentHome->getTitle()
|
||||
));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($currentHome->getName() === $orgHome->getName()) {
|
||||
// There is no dashboard home diff so clear all the dashboard pane
|
||||
// of the org home
|
||||
$orgHome->setEntries([]);
|
||||
}
|
||||
|
||||
$conn = Dashboard::getConn();
|
||||
$conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$this->dashboard->manageHome($currentHome);
|
||||
$currentHome->managePanes($currentPane, $orgHome);
|
||||
$this->dashboard->manageEntry($currentHome);
|
||||
$currentHome->manageEntry($currentPane, $orgHome);
|
||||
|
||||
$conn->commitTransaction();
|
||||
} catch (\Exception $err) {
|
||||
@ -139,10 +129,19 @@ class HomePaneForm extends CompatForm
|
||||
Notification::success(sprintf(t('Updated dashboard pane "%s" successfully'), $currentPane->getTitle()));
|
||||
} else {
|
||||
$home = $this->dashboard->getActiveHome();
|
||||
$home->setLabel($this->getValue('title'));
|
||||
$home->setTitle($this->getValue('title'));
|
||||
|
||||
$this->dashboard->manageHome($home);
|
||||
Notification::success(sprintf(t('Updated dashboard home "%s" successfully'), $home->getLabel()));
|
||||
$this->dashboard->manageEntry($home);
|
||||
Notification::success(sprintf(t('Updated dashboard home "%s" successfully'), $home->getTitle()));
|
||||
}
|
||||
}
|
||||
|
||||
public function load(BaseDashboard $dashboard)
|
||||
{
|
||||
$this->populate([
|
||||
'org_title' => $dashboard->getTitle(),
|
||||
'title' => $dashboard->getTitle(),
|
||||
'org_name' => $dashboard->getName()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -3,80 +3,92 @@
|
||||
namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Dashboard\Pane;
|
||||
use Icinga\Web\Notification;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class NewHomePaneForm extends CompatForm
|
||||
class NewHomePaneForm extends BaseDashboardForm
|
||||
{
|
||||
/** @var Dashboard */
|
||||
protected $dashboard;
|
||||
|
||||
public function __construct(Dashboard $dashboard)
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
parent::__construct($dashboard);
|
||||
|
||||
$requestUrl = Url::fromRequest();
|
||||
|
||||
// We need to set this explicitly needed for modals
|
||||
$this->setAction((string) $requestUrl);
|
||||
|
||||
if ($requestUrl->hasParam('home')) {
|
||||
$this->populate(['home' => $requestUrl->getParam('home')]);
|
||||
}
|
||||
}
|
||||
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
return $this->hasBeenSent()
|
||||
&& ($this->getPopulatedValue('btn_cancel')
|
||||
|| $this->getPopulatedValue('submit'));
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$populatedHome = Url::fromRequest()->getParam('home');
|
||||
$this->addElement('text', 'pane', [
|
||||
'required' => true,
|
||||
'label' => t('Title'),
|
||||
'placeholder' => t('Create new Dashboard'),
|
||||
'description' => t('Add new dashboard to this home.')
|
||||
]);
|
||||
|
||||
$homes = array_merge([self::CREATE_NEW_HOME => self::CREATE_NEW_HOME], $this->dashboard->getEntryKeyTitleArr());
|
||||
$this->addElement('select', 'home', [
|
||||
'required' => true,
|
||||
'class' => 'autosubmit',
|
||||
'value' => $populatedHome,
|
||||
'multiOptions' => $this->dashboard->getHomeKeyTitleArr(),
|
||||
'multiOptions' => $homes,
|
||||
'label' => t('Assign to Home'),
|
||||
'description' => t('A dashboard home you want to assign the new dashboard to.'),
|
||||
]);
|
||||
|
||||
$submitButton = $this->createElement('submit', 'submit', [
|
||||
'class' => 'autosubmit',
|
||||
'label' => t('Add Dashboard'),
|
||||
]);
|
||||
$this->registerElement($submitButton)->decorate($submitButton);
|
||||
if ($this->getPopulatedValue('home') === self::CREATE_NEW_HOME) {
|
||||
$this->addElement('text', 'new_home', [
|
||||
'required' => true,
|
||||
'label' => t('Dashboard Home'),
|
||||
'placeholder' => t('Enter dashboard home title'),
|
||||
'description' => t('Enter a title for the new dashboard home.'),
|
||||
]);
|
||||
}
|
||||
|
||||
$this->addElement('submit', 'btn_cancel', ['label' => t('Cancel')]);
|
||||
$this->getElement('btn_cancel')->setWrapper($submitButton->getWrapper());
|
||||
$submitButton = $this->createElement('submit', 'submit', [
|
||||
'class' => 'btn-primary',
|
||||
'label' => t('Add Dashboard')
|
||||
]);
|
||||
$this->registerElement($submitButton);
|
||||
|
||||
$formControls = $this->createFormControls();
|
||||
$formControls->add([
|
||||
$this->registerSubmitButton(t('Add Dashboard')),
|
||||
$this->createCancelButton()
|
||||
]);
|
||||
|
||||
$this->addHtml($formControls);
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
{
|
||||
$requestUrl = Url::fromRequest();
|
||||
$dashboard = $this->dashboard;
|
||||
$conn = Dashboard::getConn();
|
||||
|
||||
if ($requestUrl->getPath() === Dashboard::BASE_ROUTE . '/new-pane') {
|
||||
$home = $this->getPopulatedValue('home');
|
||||
$home = $dashboard->getHome($home);
|
||||
$selectedHome = $this->getPopulatedValue('home');
|
||||
if (! $selectedHome || $selectedHome === self::CREATE_NEW_HOME) {
|
||||
$selectedHome = $this->getPopulatedValue('new_home');
|
||||
}
|
||||
|
||||
if ($requestUrl->getPath() === Dashboard::BASE_ROUTE . '/new-pane') {
|
||||
$currentHome = new DashboardHome($selectedHome);
|
||||
if ($this->dashboard->hasEntry($currentHome->getName())) {
|
||||
$currentHome = clone $this->dashboard->getEntry($currentHome->getName());
|
||||
if ($currentHome->getName() !== $this->dashboard->getActiveHome()->getName()) {
|
||||
$currentHome->setActive()->loadDashboardEntries();
|
||||
}
|
||||
}
|
||||
|
||||
$pane = new Pane($this->getPopulatedValue('pane'));
|
||||
$conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$pane = new Pane($this->getPopulatedValue('pane'));
|
||||
$home->managePanes($pane);
|
||||
$this->dashboard->manageEntry($currentHome);
|
||||
$currentHome->manageEntry($pane);
|
||||
|
||||
$conn->commitTransaction();
|
||||
} catch (\Exception $err) {
|
||||
@ -85,8 +97,6 @@ class NewHomePaneForm extends CompatForm
|
||||
}
|
||||
|
||||
Notification::success('Added dashboard successfully');
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,21 +5,14 @@
|
||||
namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class RemoveDashletForm extends CompatForm
|
||||
class RemoveDashletForm extends BaseDashboardForm
|
||||
{
|
||||
/** @var Dashboard */
|
||||
protected $dashboard;
|
||||
|
||||
public function __construct(Dashboard $dashboard)
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
|
||||
$this->setAction((string) Url::fromRequest());
|
||||
return $this->hasBeenSent() && $this->getPopulatedValue('btn_remove');
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
@ -29,17 +22,20 @@ class RemoveDashletForm extends CompatForm
|
||||
Url::fromRequest()->getParam('dashlet')
|
||||
)));
|
||||
|
||||
$this->addElement('submit', 'remove_dashlet', ['label' => t('Remove Dashlet')]);
|
||||
$submit = $this->registerSubmitButton(t('Remove Dashlet'));
|
||||
$submit->setName('btn_remove');
|
||||
|
||||
$this->addHtml($submit);
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
{
|
||||
$requestUrl = Url::fromRequest();
|
||||
$home = $this->dashboard->getActiveHome();
|
||||
$pane = $home->getPane($requestUrl->getParam('pane'));
|
||||
$pane = $home->getEntry($requestUrl->getParam('pane'));
|
||||
|
||||
$dashlet = $requestUrl->getParam('dashlet');
|
||||
$pane->removeDashlet($dashlet);
|
||||
$pane->removeEntry($dashlet);
|
||||
|
||||
Notification::success(sprintf(t('Removed dashlet "%s" successfully'), $dashlet));
|
||||
}
|
||||
|
@ -6,24 +6,32 @@ namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class RemoveHomePaneForm extends CompatForm
|
||||
class RemoveHomePaneForm extends BaseDashboardForm
|
||||
{
|
||||
/** @var Dashboard */
|
||||
protected $dashboard;
|
||||
|
||||
public function __construct(Dashboard $dashboard)
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
|
||||
$this->setAction((string) Url::fromRequest());
|
||||
return $this->hasBeenSent() && $this->getPopulatedValue('btn_remove');
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$this->addElement('submit', 'btn_remove', ['label' => t('Remove Home')]);
|
||||
$requestRoute = Url::fromRequest();
|
||||
$label = t('Remove Home');
|
||||
$message = sprintf(t('Please confirm removal of dashboard home "%s"'), $requestRoute->getParam('home'));
|
||||
if ($requestRoute->getPath() === Dashboard::BASE_ROUTE . '/remove-pane') {
|
||||
$label = t('Remove Pane');
|
||||
$message = sprintf(t('Please confirm removal of dashboard pane "%s"'), $requestRoute->getParam('pane'));
|
||||
}
|
||||
|
||||
$this->addHtml(HtmlElement::create('h1', null, $message));
|
||||
|
||||
$submit = $this->registerSubmitButton($label);
|
||||
$submit->setName('btn_remove');
|
||||
|
||||
$this->addHtml($submit);
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
@ -32,12 +40,12 @@ class RemoveHomePaneForm extends CompatForm
|
||||
$home = $this->dashboard->getActiveHome();
|
||||
|
||||
if ($requestUrl->getPath() === Dashboard::BASE_ROUTE . '/remove-home') {
|
||||
$this->dashboard->removeHome($home);
|
||||
$this->dashboard->removeEntry($home);
|
||||
|
||||
Notification::success(sprintf(t('Removed dashboard home "%s" successfully'), $home->getLabel()));
|
||||
Notification::success(sprintf(t('Removed dashboard home "%s" successfully'), $home->getTitle()));
|
||||
} else {
|
||||
$pane = $home->getPane($requestUrl->getParam('pane'));
|
||||
$home->removePane($pane);
|
||||
$pane = $home->getEntry($requestUrl->getParam('pane'));
|
||||
$home->removeEntry($pane);
|
||||
|
||||
Notification::success(sprintf(t('Removed dashboard pane "%s" successfully'), $pane->getTitle()));
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
namespace Icinga\Forms\Dashboard;
|
||||
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
|
||||
@ -43,12 +43,12 @@ class WelcomeForm extends CompatForm
|
||||
protected function onSuccess()
|
||||
{
|
||||
if ($this->getPopulatedValue('btn_use_defaults')) {
|
||||
$home = $this->dashboard->getHome(DashboardHome::DEFAULT_HOME);
|
||||
$home = $this->dashboard->getEntry(DashboardHome::DEFAULT_HOME);
|
||||
$conn = Dashboard::getConn();
|
||||
$conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$home->managePanes($this->dashboard->getSystemDefaults(), null, true);
|
||||
$home->manageEntry($this->dashboard->getSystemDefaults(), null, true);
|
||||
|
||||
$conn->commitTransaction();
|
||||
} catch (\Exception $err) {
|
||||
|
@ -6,7 +6,7 @@ use Icinga\Web\Widget\SearchDashboard;
|
||||
$searchDashboard = new SearchDashboard();
|
||||
$searchDashboard->setUser($this->Auth()->getUser());
|
||||
|
||||
if ($searchDashboard->search('dummy')->getActiveHome()->getPane('search')->hasDashlets()): ?>
|
||||
if (! $searchDashboard->search('dummy')->getActiveHome()->getEntry('search')->hasEntries()): ?>
|
||||
<form action="<?= $this->href('search') ?>" method="get" role="search" class="search-control">
|
||||
<input type="text" name="q" id="search" class="search search-input" required
|
||||
placeholder="<?= $this->translate('Search') ?> …"
|
||||
|
@ -5,9 +5,7 @@ namespace Icinga\Common;
|
||||
trait DataExtractor
|
||||
{
|
||||
/**
|
||||
* Extract data from array to this class's properties
|
||||
*
|
||||
* Unknown properties (no matching setter) are ignored
|
||||
* Extract data from array to this class's properties Unknown properties (no matching setter) are ignored
|
||||
*
|
||||
* @param array $data
|
||||
*
|
||||
@ -28,9 +26,13 @@ trait DataExtractor
|
||||
/**
|
||||
* Get this class's structure as array
|
||||
*
|
||||
* Stringifies the attrs or set to null if it doesn't have a value, when $stringify is true
|
||||
*
|
||||
* @param bool $stringify Whether, the attributes should be returned unmodified
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
public function toArray($stringify = true)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
267
library/Icinga/Web/Dashboard/Common/BaseDashboard.php
Normal file
267
library/Icinga/Web/Dashboard/Common/BaseDashboard.php
Normal file
@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
use Icinga\Common\DataExtractor;
|
||||
|
||||
/**
|
||||
* Base class for all dashboard widget types
|
||||
*
|
||||
* All Icinga Web dashboard widgets should extend this class
|
||||
*/
|
||||
abstract class BaseDashboard implements DashboardEntry
|
||||
{
|
||||
use DataExtractor;
|
||||
|
||||
/**
|
||||
* Not translatable name of this widget
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The title of this widget
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* Unique identifier of this widget
|
||||
*
|
||||
* @var int|string
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The widget's description
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* The priority order of this widget
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $order = 0;
|
||||
|
||||
/**
|
||||
* Name of the owner/creator of this widget
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $owner;
|
||||
|
||||
/**
|
||||
* Create a new widget
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $properties
|
||||
*/
|
||||
public function __construct($name, array $properties = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->title = $name;
|
||||
|
||||
if (! empty($properties)) {
|
||||
$this->fromArray($properties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this widget's unique identifier
|
||||
*
|
||||
* @param int|string $uuid
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUuid($uuid)
|
||||
{
|
||||
$this->uuid = $uuid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this widget's unique identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUuid()
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this widget
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of this widget
|
||||
*
|
||||
* @param string $title
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of this widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title !== null ? $this->title : $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the owner of this widget
|
||||
*
|
||||
* @param string $owner
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOwner($owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get owner of this widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOwner()
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the widget's description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the widget's description
|
||||
*
|
||||
* @param string $description
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the priority order of this widget
|
||||
*
|
||||
* @param int $order
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPriority(int $order)
|
||||
{
|
||||
$this->order = $order;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the priority order of this widget
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
public function hasEntries()
|
||||
{
|
||||
}
|
||||
|
||||
public function getEntry($name)
|
||||
{
|
||||
}
|
||||
|
||||
public function hasEntry($name)
|
||||
{
|
||||
}
|
||||
|
||||
public function getEntries()
|
||||
{
|
||||
}
|
||||
|
||||
public function setEntries(array $entries)
|
||||
{
|
||||
}
|
||||
|
||||
public function addEntry(BaseDashboard $dashboard)
|
||||
{
|
||||
}
|
||||
|
||||
public function createEntry($name, $url = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function getEntryKeyTitleArr()
|
||||
{
|
||||
}
|
||||
|
||||
public function removeEntry($entry)
|
||||
{
|
||||
}
|
||||
|
||||
public function removeEntries(array $entries = [])
|
||||
{
|
||||
}
|
||||
|
||||
public function manageEntry($entry, BaseDashboard $origin = null, $updateChildEntries = false)
|
||||
{
|
||||
}
|
||||
|
||||
public function loadDashboardEntries($name = '')
|
||||
{
|
||||
}
|
||||
|
||||
public function rewindEntries()
|
||||
{
|
||||
}
|
||||
}
|
126
library/Icinga/Web/Dashboard/Common/DashboardControls.php
Normal file
126
library/Icinga/Web/Dashboard/Common/DashboardControls.php
Normal file
@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
|
||||
use function ipl\Stdlib\get_php_type;
|
||||
|
||||
trait DashboardControls
|
||||
{
|
||||
/**
|
||||
* A list of @see BaseDashboard assigned to this dashboard widget
|
||||
*
|
||||
* @var BaseDashboard
|
||||
*/
|
||||
private $dashboards = [];
|
||||
|
||||
public function hasEntries()
|
||||
{
|
||||
return ! empty($this->dashboards);
|
||||
}
|
||||
|
||||
public function getEntry($name)
|
||||
{
|
||||
if (! $this->hasEntry($name)) {
|
||||
throw new ProgrammingError('Trying to retrieve invalid dashboard entry "%s"', $name);
|
||||
}
|
||||
|
||||
return $this->dashboards[$name];
|
||||
}
|
||||
|
||||
public function hasEntry($name)
|
||||
{
|
||||
return array_key_exists($name, $this->dashboards);
|
||||
}
|
||||
|
||||
public function getEntries()
|
||||
{
|
||||
// An entry can be added individually afterwards, it might be the case that the priority
|
||||
// order gets mixed up, so we have to sort things here before being able to render them
|
||||
uasort($this->dashboards, function (BaseDashboard $x, BaseDashboard $y) {
|
||||
return $x->getPriority() - $y->getPriority();
|
||||
});
|
||||
|
||||
return $this->dashboards;
|
||||
}
|
||||
|
||||
public function setEntries(array $entries)
|
||||
{
|
||||
$this->dashboards = $entries;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addEntry(BaseDashboard $dashboard)
|
||||
{
|
||||
if ($this->hasEntry($dashboard->getName())) {
|
||||
$this->getEntry($dashboard->getName())->fromArray($dashboard->toArray(false));
|
||||
} else {
|
||||
$this->dashboards[$dashboard->getName()] = $dashboard;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEntryKeyTitleArr()
|
||||
{
|
||||
$dashboards = [];
|
||||
foreach ($this->getEntries() as $dashboard) {
|
||||
$dashboards[$dashboard->getName()] = $dashboard->getTitle();
|
||||
}
|
||||
|
||||
return $dashboards;
|
||||
}
|
||||
|
||||
public function removeEntries(array $entries = [])
|
||||
{
|
||||
$dashboards = ! empty($entries) ? $entries : $this->getEntries();
|
||||
foreach ($dashboards as $dashboard) {
|
||||
$this->removeEntry($dashboard);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function createEntry($name, $url = null)
|
||||
{
|
||||
}
|
||||
|
||||
public function rewindEntries()
|
||||
{
|
||||
return reset($this->dashboards);
|
||||
}
|
||||
|
||||
public function reorderWidget(BaseDashboard $dashboard, $position, Sortable $origin = null)
|
||||
{
|
||||
if ($origin && ! $origin instanceof $this) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
__METHOD__ . ' expects parameter "$origin" to be an instance of "%s". Got "%s" instead.',
|
||||
get_php_type($this),
|
||||
get_php_type($origin)
|
||||
));
|
||||
}
|
||||
|
||||
if (! $this->hasEntry($dashboard->getName())) {
|
||||
$dashboard->setPriority($position);
|
||||
$data = [$dashboard];
|
||||
} else {
|
||||
$data = array_values($this->getEntries());
|
||||
array_splice($data, array_search($dashboard->getName(), array_keys($this->getEntries())), 1);
|
||||
array_splice($data, $position, 0, [$dashboard]);
|
||||
}
|
||||
|
||||
foreach ($data as $index => $item) {
|
||||
if (count($data) !== 1) {
|
||||
$item->setPriority($index);
|
||||
}
|
||||
|
||||
$this->manageEntry($item, $dashboard->getName() === $item->getName() ? $origin : null);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
131
library/Icinga/Web/Dashboard/Common/DashboardEntry.php
Normal file
131
library/Icinga/Web/Dashboard/Common/DashboardEntry.php
Normal file
@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
use ipl\Web\Url;
|
||||
|
||||
/**
|
||||
* Represents a dashboard widget types
|
||||
*/
|
||||
interface DashboardEntry
|
||||
{
|
||||
/**
|
||||
* Check whether this widget doesn't contain any dashboard entries
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasEntries();
|
||||
|
||||
/**
|
||||
* Get a dashboard entry by the given name if exists
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return BaseDashboard
|
||||
*/
|
||||
public function getEntry($name);
|
||||
|
||||
/**
|
||||
* Get whether the given dashboard entry exists
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasEntry($name);
|
||||
|
||||
/**
|
||||
* Get all dashboard entries of this widget
|
||||
*
|
||||
* @return BaseDashboard[]
|
||||
*/
|
||||
public function getEntries();
|
||||
|
||||
/**
|
||||
* Set dashboard entries of this widget
|
||||
*
|
||||
* @param BaseDashboard[] $entries
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setEntries(array $entries);
|
||||
|
||||
/**
|
||||
* Add a new dashboard entry to this widget
|
||||
*
|
||||
* @param BaseDashboard $dashboard
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addEntry(BaseDashboard $dashboard);
|
||||
|
||||
/**
|
||||
* Create and add a new entry to this widget
|
||||
*
|
||||
* @param string $name
|
||||
* @param ?string|Url $url
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function createEntry($name, $url = null);
|
||||
|
||||
/**
|
||||
* Get an array with entry name=>title format
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getEntryKeyTitleArr();
|
||||
|
||||
/**
|
||||
* Remove the given entry from this widget
|
||||
*
|
||||
* @param BaseDashboard|string $entry
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeEntry($entry);
|
||||
|
||||
/**
|
||||
* Removes the given list of entries from this widget
|
||||
*
|
||||
* If there is no entries passed, all the available entries of this widget will be removed
|
||||
*
|
||||
* @param BaseDashboard[] $entries
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeEntries(array $entries = []);
|
||||
|
||||
/**
|
||||
* Manage the given widget(s)
|
||||
*
|
||||
* Performs all kinds of database actions for the given widget(s) except the DELETE action. If you want to
|
||||
* move pane(s)|dashlet(s) from another to this widget you have to also provide the origin from which the
|
||||
* given entry(ies) originated
|
||||
*
|
||||
* @param BaseDashboard|BaseDashboard[] $entry
|
||||
* @param ?BaseDashboard $origin
|
||||
* @param bool $updateChildEntries
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function manageEntry($entry, BaseDashboard $origin = null, $updateChildEntries = false);
|
||||
|
||||
/**
|
||||
* Load all the assigned entries to this widget
|
||||
*
|
||||
* @param ?string $name Name of the dashboard widget you want to load the dashboard entries for
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loadDashboardEntries($name = '');
|
||||
|
||||
/**
|
||||
* Reset the current position of the internal dashboard entries pointer
|
||||
*
|
||||
* @return false|BaseDashboard
|
||||
*/
|
||||
public function rewindEntries();
|
||||
}
|
@ -11,10 +11,10 @@ use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Model;
|
||||
use Icinga\User;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Dashboard\Dashlet;
|
||||
use Icinga\Web\Dashboard\Pane;
|
||||
use Icinga\Web\HomeMenu;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use ipl\Orm\Query;
|
||||
use ipl\Sql\Connection;
|
||||
use ipl\Sql\Expression;
|
||||
@ -38,17 +38,10 @@ trait DashboardManager
|
||||
*/
|
||||
private static $defaultPanes = [];
|
||||
|
||||
/**
|
||||
* A list of @see DashboardHome
|
||||
*
|
||||
* @var DashboardHome[]
|
||||
*/
|
||||
private $homes = [];
|
||||
|
||||
public function load()
|
||||
{
|
||||
$this->loadHomesFromMenu();
|
||||
$this->loadDashboards();
|
||||
$this->setEntries((new HomeMenu())->loadHomes());
|
||||
$this->loadDashboardEntries();
|
||||
|
||||
$this->initGetDefaultHome();
|
||||
self::deployModuleDashlets();
|
||||
@ -84,115 +77,33 @@ trait DashboardManager
|
||||
return sha1($name, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load dashboard homes from the navigation menu
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loadHomesFromMenu()
|
||||
public function loadDashboardEntries($name = '')
|
||||
{
|
||||
$menu = new HomeMenu();
|
||||
foreach ($menu->getItem('dashboard')->getChildren() as $home) {
|
||||
if (! $home instanceof DashboardHome) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->homes[$home->getName()] = $home;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load dashboards assigned to the given home or active home being loaded
|
||||
*
|
||||
* @param ?string $name Name of the dashboard home you want to load the dashboards for
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loadDashboards($name = null)
|
||||
{
|
||||
if ($name && $this->hasHome($name)) {
|
||||
$home = $this->getHome($name);
|
||||
if ($name && $this->hasEntry($name)) {
|
||||
$home = $this->getEntry($name);
|
||||
} else {
|
||||
$requestRoute = Url::fromRequest();
|
||||
if ($requestRoute->getPath() === Dashboard::BASE_ROUTE) {
|
||||
$home = $this->initGetDefaultHome();
|
||||
} else {
|
||||
$homeParam = $requestRoute->getParam('home');
|
||||
if (empty($homeParam) || ! $this->hasHome($homeParam)) {
|
||||
if (! ($home = $this->rewindHomes())) {
|
||||
if (empty($homeParam) || ! $this->hasEntry($homeParam)) {
|
||||
if (! ($home = $this->rewindEntries())) {
|
||||
// No dashboard homes
|
||||
return $this;
|
||||
}
|
||||
} else {
|
||||
$home = $this->getHome($homeParam);
|
||||
$home = $this->getEntry($homeParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->activateHome($home);
|
||||
$home->loadPanesFromDB();
|
||||
$home->loadDashboardEntries();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dashboard home by the given name
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return DashboardHome
|
||||
*/
|
||||
public function getHome($name)
|
||||
{
|
||||
if ($this->hasHome($name)) {
|
||||
return $this->homes[$name];
|
||||
}
|
||||
|
||||
throw new ProgrammingError('Trying to retrieve invalid dashboard home "%s"', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dashboard homes assigned to the active user
|
||||
*
|
||||
* @return DashboardHome[]
|
||||
*/
|
||||
public function getHomes()
|
||||
{
|
||||
return $this->homes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this user's dashboard homes
|
||||
*
|
||||
* @param DashboardHome|DashboardHome[] $homes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setHomes($homes)
|
||||
{
|
||||
if ($homes instanceof DashboardHome) {
|
||||
$homes = [$homes->getName() => $homes];
|
||||
}
|
||||
|
||||
$this->homes = $homes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the given home exist
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasHome($name)
|
||||
{
|
||||
return array_key_exists($name, $this->homes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the given home and deactivates all other active homes
|
||||
*
|
||||
@ -207,7 +118,7 @@ trait DashboardManager
|
||||
$activeHome->setActive(false);
|
||||
}
|
||||
|
||||
$home->setActive(true);
|
||||
$home->setActive();
|
||||
|
||||
return $this;
|
||||
}
|
||||
@ -219,7 +130,8 @@ trait DashboardManager
|
||||
*/
|
||||
public function getActiveHome()
|
||||
{
|
||||
foreach ($this->getHomes() as $home) {
|
||||
/** @var DashboardHome $home */
|
||||
foreach ($this->getEntries() as $home) {
|
||||
if ($home->getActive()) {
|
||||
return $home;
|
||||
}
|
||||
@ -228,123 +140,59 @@ trait DashboardManager
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current position of the internal dashboard homes pointer
|
||||
*
|
||||
* @return false|DashboardHome
|
||||
*/
|
||||
public function rewindHomes()
|
||||
{
|
||||
return reset($this->homes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given home
|
||||
*
|
||||
* @param DashboardHome|string $home
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeHome($home)
|
||||
public function removeEntry($home)
|
||||
{
|
||||
$name = $home instanceof DashboardHome ? $home->getName() : $home;
|
||||
if (! $this->hasHome($name)) {
|
||||
if (! $this->hasEntry($name)) {
|
||||
throw new ProgrammingError('Trying to remove invalid dashboard home "%s"', $name);
|
||||
}
|
||||
|
||||
$home = $home instanceof DashboardHome ? $home : $this->getHome($home);
|
||||
if (! $home->isDisabled()) {
|
||||
$home->removePanes();
|
||||
|
||||
$home = $home instanceof DashboardHome ? $home : $this->getEntry($home);
|
||||
$home->removeEntries();
|
||||
if ($home->getName() !== DashboardHome::DEFAULT_HOME) {
|
||||
self::getConn()->delete(DashboardHome::TABLE, ['id = ?' => $home->getUuid()]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all|given list of dashboard homes
|
||||
*
|
||||
* @param DashboardHome[] $homes Optional list of dashboard homes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeHomes(array $homes = [])
|
||||
{
|
||||
$homes = ! empty($homes) ? $homes : $this->getHomes();
|
||||
foreach ($homes as $home) {
|
||||
$this->removeHome($home);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the given home
|
||||
*
|
||||
* @param DashboardHome $home
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function manageHome(DashboardHome $home)
|
||||
public function manageEntry($entry, BaseDashboard $origin = null, $updateChildEntries = false)
|
||||
{
|
||||
$conn = self::getConn();
|
||||
if (! $this->hasHome($home->getName())) {
|
||||
$home = $entry;
|
||||
if (! $this->hasEntry($home->getName())) {
|
||||
$priority = $home->getName() === DashboardHome::DEFAULT_HOME ? 0 : count($this->getEntries());
|
||||
$conn->insert(DashboardHome::TABLE, [
|
||||
'name' => $home->getName(),
|
||||
'label' => $home->getLabel(),
|
||||
'label' => $home->getTitle(),
|
||||
'username' => self::getUser()->getUsername(),
|
||||
'priority' => count($this->getHomes()) + 1,
|
||||
// highest priority is 0, so count($entries) are always lowest prio + 1
|
||||
'priority' => $priority,
|
||||
'type' => $home->getType() !== Dashboard::SYSTEM ? $home->getType() : Dashboard::PRIVATE_DS
|
||||
]);
|
||||
|
||||
$home->setUuid($conn->lastInsertId());
|
||||
} elseif ($home->getName() !== DashboardHome::DEFAULT_HOME) {
|
||||
$conn->update(DashboardHome::TABLE, [
|
||||
'label' => $home->getLabel(),
|
||||
'priority' => $home->getPriority()
|
||||
], ['id = ?' => $home->getUuid()]);
|
||||
} else {
|
||||
$conn->update(DashboardHome::TABLE, ['priority' => $home->getPriority()], ['id = ?' => $home->getUuid()]);
|
||||
$conn->update(DashboardHome::TABLE, ['label' => $home->getTitle()], ['id = ?' => $home->getUuid()]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array with home name=>title format
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHomeKeyTitleArr()
|
||||
{
|
||||
$panes = [];
|
||||
foreach ($this->getHomes() as $home) {
|
||||
if ($home->isDisabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$panes[$home->getName()] = $home->getLabel();
|
||||
}
|
||||
|
||||
return $panes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get and|or init the default dashboard home
|
||||
*
|
||||
* @return DashboardHome
|
||||
* @return BaseDashboard
|
||||
*/
|
||||
public function initGetDefaultHome()
|
||||
{
|
||||
if ($this->hasHome(DashboardHome::DEFAULT_HOME)) {
|
||||
return $this->getHome(DashboardHome::DEFAULT_HOME);
|
||||
if ($this->hasEntry(DashboardHome::DEFAULT_HOME)) {
|
||||
return $this->getEntry(DashboardHome::DEFAULT_HOME);
|
||||
}
|
||||
|
||||
$default = new DashboardHome(DashboardHome::DEFAULT_HOME);
|
||||
$this->manageHome($default);
|
||||
|
||||
$this->homes[$default->getName()] = $default;
|
||||
$this->manageEntry($default);
|
||||
$this->addEntry($default);
|
||||
|
||||
return $default;
|
||||
}
|
||||
@ -400,7 +248,8 @@ trait DashboardManager
|
||||
foreach ($moduleManager->getLoadedModules() as $module) {
|
||||
foreach ($module->getDashboard() as $dashboardPane) {
|
||||
$priority = 0;
|
||||
foreach ($dashboardPane->getDashlets() as $dashlet) {
|
||||
/** @var Dashlet $dashlet */
|
||||
foreach ($dashboardPane->getEntries() as $dashlet) {
|
||||
$uuid = self::getSHA1($module->getName() . $dashboardPane->getName() . $dashlet->getName());
|
||||
$dashlet
|
||||
->setUuid($uuid)
|
||||
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
trait DisableWidget
|
||||
{
|
||||
/**
|
||||
* A flag whether this widget is disabled
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $disabled = false;
|
||||
|
||||
/**
|
||||
* Set whether this widget should be disabled
|
||||
*
|
||||
* @param bool $disable
|
||||
*/
|
||||
public function disable(bool $disable = true)
|
||||
{
|
||||
$this->disabled = $disable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this widget is disabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDisabled()
|
||||
{
|
||||
return $this->disabled;
|
||||
}
|
||||
}
|
@ -6,35 +6,82 @@ namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\Icon;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
abstract class ItemListControl extends BaseHtmlElement
|
||||
{
|
||||
protected $tag = 'div';
|
||||
|
||||
/**
|
||||
* Set a class name for the collapsible control
|
||||
* Get this item's unique html identifier
|
||||
*
|
||||
* @var string
|
||||
* @return string
|
||||
*/
|
||||
protected $collapsibleControlClass;
|
||||
protected abstract function getHtmlId();
|
||||
|
||||
protected function setCollapsibleControlClass($class)
|
||||
/**
|
||||
* Get a class name for the collapsible control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected abstract function getCollapsibleControlClass();
|
||||
|
||||
/**
|
||||
* Create an action link to be added at the end of the list
|
||||
*
|
||||
* @return HtmlElement
|
||||
*/
|
||||
protected abstract function createActionLink();
|
||||
|
||||
/**
|
||||
* Create the appropriate item list of this control
|
||||
*
|
||||
* @return HtmlElement
|
||||
*/
|
||||
protected abstract function createItemList();
|
||||
|
||||
/**
|
||||
* Assemble a header element for this item list
|
||||
*
|
||||
* @param Url $url
|
||||
* @param string $header
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function assembleHeader(Url $url, $header, $disable = false)
|
||||
{
|
||||
$this->collapsibleControlClass = $class;
|
||||
$header = HtmlElement::create('h1', ['class' => 'collapsible-header'], $header);
|
||||
$header->addHtml(new Link(t('Edit'), $url, [
|
||||
'class' => $disable ? 'disabled' : null,
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
|
||||
return $this;
|
||||
$this->addHtml($header);
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$this->addHtml(HtmlElement::create('div', ['class' => $this->collapsibleControlClass], [
|
||||
$this->getAttributes()->add([
|
||||
'id' => $this->getHtmlId(),
|
||||
'class' => ['collapsible'],
|
||||
'data-toggle-element' => '.dashboard-list-info',
|
||||
]);
|
||||
|
||||
$this->addHtml(HtmlElement::create('div', ['class' => $this->getCollapsibleControlClass()], [
|
||||
new Icon('angle-down', ['class' => 'expand-icon', 'title' => t('Expand')]),
|
||||
new Icon('angle-up', ['class' => 'collapse-icon', 'title' => t('Collapse')])
|
||||
]));
|
||||
|
||||
$this->getAttributes()->registerAttributeCallback('draggable', function () {
|
||||
return 'true';
|
||||
});
|
||||
$this->addHtml($this->createItemList());
|
||||
$actionLink = $this->createActionLink();
|
||||
$actionLink->getAttributes()->add([
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]);
|
||||
|
||||
$this->addHtml($actionLink);
|
||||
}
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
trait OrderWidget
|
||||
{
|
||||
/**
|
||||
* The priority order of this widget
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $order = 0;
|
||||
|
||||
/**
|
||||
* Set the priority order of this widget
|
||||
*
|
||||
* @param int $order
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPriority(int $order)
|
||||
{
|
||||
$this->order = $order;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the priority order of this widget
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPriority()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard;
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
interface OverridingWidget
|
||||
{
|
23
library/Icinga/Web/Dashboard/Common/Sortable.php
Normal file
23
library/Icinga/Web/Dashboard/Common/Sortable.php
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\Common;
|
||||
|
||||
/**
|
||||
* Sortable interface that allows to reorder the provided dashboard entry
|
||||
* and update the database accordingly
|
||||
*/
|
||||
interface Sortable
|
||||
{
|
||||
/**
|
||||
* Insert the dashboard entry at the given position within this dashboard entries
|
||||
*
|
||||
* @param BaseDashboard $dashboard
|
||||
* @param $position
|
||||
* @param Sortable|null $origin
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function reorderWidget(BaseDashboard $dashboard, $position, Sortable $origin = null);
|
||||
}
|
@ -6,8 +6,9 @@ namespace Icinga\Web\Dashboard;
|
||||
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Dashboard\Common\DashboardControls;
|
||||
use Icinga\Web\Dashboard\Common\DashboardEntry;
|
||||
use Icinga\Web\Dashboard\Common\DashboardManager;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\Form;
|
||||
use ipl\Html\HtmlElement;
|
||||
@ -23,9 +24,10 @@ use ipl\Web\Widget\Tabs;
|
||||
* - Dashboard/Home: Shows all panes belonging to this home
|
||||
*
|
||||
*/
|
||||
class Dashboard extends BaseHtmlElement
|
||||
class Dashboard extends BaseHtmlElement implements DashboardEntry
|
||||
{
|
||||
use DashboardManager;
|
||||
use DashboardControls;
|
||||
|
||||
/**
|
||||
* Base path of our new dashboards controller
|
||||
@ -35,8 +37,7 @@ class Dashboard extends BaseHtmlElement
|
||||
const BASE_ROUTE = 'dashboards';
|
||||
|
||||
/**
|
||||
* System dashboards are provided by the modules in PHP code
|
||||
* and are available to all users
|
||||
* System dashboards are provided by the modules in PHP code and are available to all users
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
@ -51,8 +52,7 @@ class Dashboard extends BaseHtmlElement
|
||||
const PUBLIC_DS = 'public';
|
||||
|
||||
/**
|
||||
* Private dashboards are created by any user and are only
|
||||
* available to this user
|
||||
* Private dashboards are created by any user and are only available to this user
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
@ -136,15 +136,11 @@ class Dashboard extends BaseHtmlElement
|
||||
}
|
||||
|
||||
$this->tabs->disableLegacyExtensions();
|
||||
if (! $activeHome || $activeHome->isDisabled()) {
|
||||
if (! $activeHome) {
|
||||
return $this->tabs;
|
||||
}
|
||||
|
||||
foreach ($activeHome->getPanes() as $key => $pane) {
|
||||
if ($pane->isDisabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($activeHome->getEntries() as $key => $pane) {
|
||||
if (! $this->tabs->get($key)) {
|
||||
$this->tabs->add(
|
||||
$key,
|
||||
@ -173,12 +169,9 @@ class Dashboard extends BaseHtmlElement
|
||||
{
|
||||
$active = null;
|
||||
$activeHome = $this->getActiveHome();
|
||||
|
||||
foreach ($activeHome->getPanes() as $key => $pane) {
|
||||
if ($pane->isDisabled() === false) {
|
||||
$active = $key;
|
||||
break;
|
||||
}
|
||||
foreach ($activeHome->getEntries() as $key => $pane) {
|
||||
$active = $key;
|
||||
break;
|
||||
}
|
||||
|
||||
if ($active !== null) {
|
||||
@ -211,7 +204,7 @@ class Dashboard extends BaseHtmlElement
|
||||
|
||||
if (! $active) {
|
||||
if ($active = Url::fromRequest()->getParam($this->tabParam)) {
|
||||
if ($activeHome->hasPane($active)) {
|
||||
if ($activeHome->hasEntry($active)) {
|
||||
$this->activate($active);
|
||||
} else {
|
||||
throw new ProgrammingError('Try to get an inexistent pane.');
|
||||
@ -223,7 +216,7 @@ class Dashboard extends BaseHtmlElement
|
||||
$active = $active->getName();
|
||||
}
|
||||
|
||||
$panes = $activeHome->getPanes();
|
||||
$panes = $activeHome->getEntries();
|
||||
if (isset($panes[$active])) {
|
||||
return $panes[$active];
|
||||
}
|
||||
@ -241,7 +234,7 @@ class Dashboard extends BaseHtmlElement
|
||||
protected function assemble()
|
||||
{
|
||||
$activeHome = $this->getActiveHome();
|
||||
if (! $activeHome || ($activeHome->getName() === DashboardHome::DEFAULT_HOME && ! $activeHome->hasPanes())) {
|
||||
if (! $activeHome || (! $activeHome->hasEntries() && $activeHome->getName() === DashboardHome::DEFAULT_HOME)) {
|
||||
$this->setAttribute('class', 'content welcome-view');
|
||||
$wrapper = HtmlElement::create('div', ['class' => 'dashboard-introduction']);
|
||||
|
||||
@ -266,19 +259,21 @@ class Dashboard extends BaseHtmlElement
|
||||
|
||||
$wrapper->addHtml($this->welcomeForm);
|
||||
$this->addHtml($wrapper);
|
||||
} elseif (! empty($activeHome->getPanes(true))) {
|
||||
$dashlets = $this->getActivePane()->getDashlets();
|
||||
} elseif (! $activeHome->hasEntries()) {
|
||||
$this->setAttribute('class', 'content');
|
||||
$this->addHtml(HtmlElement::create('h1', null, t('No dashboard added to this dashboard home')));
|
||||
} else {
|
||||
$activePane = $this->getActivePane();
|
||||
$this->setAttribute('data-icinga-pane', $activeHome->getName() . '|' . $this->getActivePane()->getName());
|
||||
|
||||
if (empty($dashlets)) {
|
||||
if (! $activePane->hasEntries()) {
|
||||
$this->setAttribute('class', 'content');
|
||||
$dashlets = HtmlElement::create('h1', null, t('No dashlet added to this pane.'));
|
||||
$this->addHtml(HtmlElement::create('h1', null, t('No dashlet added to this pane.')));
|
||||
} else {
|
||||
foreach ($activePane->getEntries() as $dashlet) {
|
||||
$this->addHtml($dashlet->getHtml());
|
||||
}
|
||||
}
|
||||
|
||||
$this->add($dashlets);
|
||||
} else {
|
||||
// TODO: What to do with dashboard homes without any dashboards??
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
240
library/Icinga/Web/Dashboard/DashboardHome.php
Normal file
240
library/Icinga/Web/Dashboard/DashboardHome.php
Normal file
@ -0,0 +1,240 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Dashboard\Common\BaseDashboard;
|
||||
use Icinga\Web\Dashboard\Common\DashboardControls;
|
||||
use Icinga\Web\Dashboard\Common\Sortable;
|
||||
use Icinga\Web\Navigation\DashboardHomeItem;
|
||||
use ipl\Stdlib\Filter;
|
||||
|
||||
use function ipl\Stdlib\get_php_type;
|
||||
|
||||
class DashboardHome extends BaseDashboard implements Sortable
|
||||
{
|
||||
use DashboardControls;
|
||||
|
||||
/**
|
||||
* Name of the default home
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_HOME = 'Default Home';
|
||||
|
||||
/**
|
||||
* Database table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'dashboard_home';
|
||||
|
||||
/**
|
||||
* A type of this dashboard home
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = Dashboard::SYSTEM;
|
||||
|
||||
protected $active;
|
||||
|
||||
/**
|
||||
* Create a new dashboard home from the given home item
|
||||
*
|
||||
* @param DashboardHomeItem $homeItem
|
||||
*
|
||||
* @return DashboardHome
|
||||
*/
|
||||
public static function create(DashboardHomeItem $homeItem)
|
||||
{
|
||||
return new self($homeItem->getName(), $homeItem->getAttributes());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this home is active
|
||||
*
|
||||
* DB dashboards will load only when this home has been activated
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setActive($active = true)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this home has been activated
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getActive()
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this dashboard home
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of this dashboard home
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function removeEntry($pane)
|
||||
{
|
||||
$name = $pane instanceof Pane ? $pane->getName() : $pane;
|
||||
if (! $this->hasEntry($name)) {
|
||||
throw new ProgrammingError('Trying to remove invalid dashboard pane "%s"', $name);
|
||||
}
|
||||
|
||||
$pane = $pane instanceof Pane ? $pane : $this->getEntry($pane);
|
||||
if (! $pane->isOverriding()) {
|
||||
$pane->removeEntries();
|
||||
|
||||
Dashboard::getConn()->delete(Pane::TABLE, [
|
||||
'id = ?' => $pane->getUuid(),
|
||||
'home_id = ?' => $this->getUuid()
|
||||
]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function loadDashboardEntries($name = '')
|
||||
{
|
||||
if (! $this->getActive()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->setEntries([]);
|
||||
$panes = \Icinga\Model\Pane::on(Dashboard::getConn())->utilize('home');
|
||||
$panes
|
||||
->filter(Filter::equal('home_id', $this->getUuid()))
|
||||
->filter(Filter::equal('username', Dashboard::getUser()->getUsername()));
|
||||
|
||||
foreach ($panes as $pane) {
|
||||
$newPane = new Pane($pane->name);
|
||||
$newPane->fromArray([
|
||||
'uuid' => $pane->id,
|
||||
'title' => $pane->label,
|
||||
'priority' => $pane->priority,
|
||||
'home' => $this
|
||||
]);
|
||||
|
||||
$newPane->loadDashboardEntries($name);
|
||||
$this->addEntry($newPane);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function createEntry($name, $url = null)
|
||||
{
|
||||
$entry = new Pane($name);
|
||||
$entry->setHome($this);
|
||||
|
||||
$this->addEntry($entry);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function manageEntry($entry, BaseDashboard $origin = null, $updateChildEntries = false)
|
||||
{
|
||||
$user = Dashboard::getUser();
|
||||
$conn = Dashboard::getConn();
|
||||
|
||||
$panes = is_array($entry) ? $entry : [$entry];
|
||||
// highest priority is 0, so count($entries) are all always lowest prio + 1
|
||||
$order = count($this->getEntries());
|
||||
|
||||
if ($origin && ! $origin instanceof DashboardHome) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
__METHOD__ . ' expects parameter "$origin" to be an instance of "%s". Got "%s" instead.',
|
||||
get_php_type($this),
|
||||
get_php_type($origin)
|
||||
));
|
||||
}
|
||||
|
||||
/** @var Pane $pane */
|
||||
foreach ($panes as $pane) {
|
||||
$uuid = Dashboard::getSHA1($user->getUsername() . $this->getName() . $pane->getName());
|
||||
if (! $pane->isOverriding()) {
|
||||
if (! $this->hasEntry($pane->getName()) && (! $origin || ! $origin->hasEntry($pane->getName()))) {
|
||||
$conn->insert(Pane::TABLE, [
|
||||
'id' => $uuid,
|
||||
'home_id' => $this->getUuid(),
|
||||
'name' => $pane->getName(),
|
||||
'label' => $pane->getTitle(),
|
||||
'username' => $user->getUsername(),
|
||||
'priority' => $order++
|
||||
]);
|
||||
} elseif (! $this->hasEntry($pane->getName()) || ! $origin || ! $origin->hasEntry($pane->getName())) {
|
||||
$filterCondition = [
|
||||
'id = ?' => $pane->getUuid(),
|
||||
'home_id = ?' => $this->getUuid()
|
||||
];
|
||||
|
||||
if ($origin && $origin->hasEntry($pane->getName())) {
|
||||
$filterCondition = [
|
||||
'id = ?' => $origin->getEntry($pane->getName())->getUuid(),
|
||||
'home_id = ?' => $origin->getUuid()
|
||||
];
|
||||
}
|
||||
|
||||
$conn->update(Pane::TABLE, [
|
||||
'id' => $uuid,
|
||||
'home_id' => $this->getUuid(),
|
||||
'label' => $pane->getTitle(),
|
||||
'priority' => $pane->getPriority()
|
||||
], $filterCondition);
|
||||
} else {
|
||||
// Failed to move the pane! Should have been handled already by the caller
|
||||
break;
|
||||
}
|
||||
|
||||
$pane->setHome($this);
|
||||
$pane->setUuid($uuid);
|
||||
}
|
||||
|
||||
if ($updateChildEntries) {
|
||||
// Those dashboard panes are usually system defaults and go up when
|
||||
// the user is clicking on the "Use System Defaults" button
|
||||
$dashlets = $pane->getEntries();
|
||||
$pane->setEntries([]);
|
||||
$pane->manageEntry($dashlets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function toArray($stringify = true)
|
||||
{
|
||||
return [
|
||||
'id' => $this->getUuid(),
|
||||
'name' => $this->getName(),
|
||||
'title' => $this->getTitle(),
|
||||
'priority' => $this->getPriority()
|
||||
];
|
||||
}
|
||||
}
|
@ -5,13 +5,10 @@
|
||||
namespace Icinga\Web\Dashboard;
|
||||
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Common\DataExtractor;
|
||||
use Icinga\Web\Dashboard\Common\DisableWidget;
|
||||
use Icinga\Web\Dashboard\Common\BaseDashboard;
|
||||
use Icinga\Web\Dashboard\Common\ModuleDashlet;
|
||||
use Icinga\Web\Dashboard\Common\OrderWidget;
|
||||
use Icinga\Web\Request;
|
||||
use Icinga\Web\Url;
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
@ -20,23 +17,13 @@ use ipl\Web\Widget\Link;
|
||||
*
|
||||
* This is the new element being used for the Dashlets view
|
||||
*/
|
||||
class Dashlet extends BaseHtmlElement
|
||||
class Dashlet extends BaseDashboard
|
||||
{
|
||||
use DisableWidget;
|
||||
use OrderWidget;
|
||||
use ModuleDashlet;
|
||||
use DataExtractor;
|
||||
|
||||
/** @var string Database table name */
|
||||
const TABLE = 'dashlet';
|
||||
|
||||
protected $tag = 'div';
|
||||
|
||||
protected $defaultAttributes = [
|
||||
'class' => 'container widget-sortable',
|
||||
'draggable' => 'true'
|
||||
];
|
||||
|
||||
/**
|
||||
* The url of this Dashlet
|
||||
*
|
||||
@ -44,19 +31,6 @@ class Dashlet extends BaseHtmlElement
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* Not translatable name of this dashlet
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* The title being displayed on top of the dashlet
|
||||
* @var
|
||||
*/
|
||||
protected $title;
|
||||
|
||||
/**
|
||||
* The pane this dashlet belongs to
|
||||
*
|
||||
@ -71,107 +45,21 @@ class Dashlet extends BaseHtmlElement
|
||||
*/
|
||||
protected $progressLabel;
|
||||
|
||||
/**
|
||||
* Unique identifier of this dashlet
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $uuid;
|
||||
|
||||
/**
|
||||
* The dashlet's description
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description;
|
||||
|
||||
/**
|
||||
* Create a new dashlet displaying the given url in the provided pane
|
||||
*
|
||||
* @param string $title The title to use for this dashlet
|
||||
* @param string $name The title to use for this dashlet
|
||||
* @param Url|string $url The url this dashlet uses for displaying information
|
||||
* @param Pane|null $pane The pane this Dashlet will be added to
|
||||
*/
|
||||
public function __construct($title, $url, Pane $pane = null)
|
||||
public function __construct($name, $url, Pane $pane = null)
|
||||
{
|
||||
$this->name = $title;
|
||||
$this->title = $title;
|
||||
parent::__construct($name);
|
||||
|
||||
$this->pane = $pane;
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the identifier of this dashlet
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUuid($id)
|
||||
{
|
||||
$this->uuid = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the unique identifier of this dashlet
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUuid()
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for this name
|
||||
*
|
||||
* @param $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for this name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the dashlets title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title !== null ? $this->title : $this->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of this dashlet
|
||||
*
|
||||
* @param string $title
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the dashlets url
|
||||
*
|
||||
@ -232,30 +120,6 @@ class Dashlet extends BaseHtmlElement
|
||||
return $this->progressLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dashlet's description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
return $this->description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dashlet's description
|
||||
*
|
||||
* @param string $description
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDescription($description)
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Pane of this dashlet
|
||||
*
|
||||
@ -280,11 +144,17 @@ class Dashlet extends BaseHtmlElement
|
||||
return $this->pane;
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
/**
|
||||
* Generate a html widget for this dashlet
|
||||
*
|
||||
* @return HtmlElement
|
||||
*/
|
||||
public function getHtml()
|
||||
{
|
||||
$dashletHtml = HtmlElement::create('div', ['class' => 'container']);
|
||||
if (! $this->getUrl()) {
|
||||
$this->addHtml(HtmlElement::create('h1', null, t($this->getTitle())));
|
||||
$this->addHtml(HtmlElement::create(
|
||||
$dashletHtml->addHtml(HtmlElement::create('h1', null, t($this->getTitle())));
|
||||
$dashletHtml->addHtml(HtmlElement::create(
|
||||
'p',
|
||||
['class' => 'error-message'],
|
||||
sprintf(t('Cannot create dashboard dashlet "%s" without valid URL'), t($this->getTitle()))
|
||||
@ -293,10 +163,10 @@ class Dashlet extends BaseHtmlElement
|
||||
$url = $this->getUrl();
|
||||
$url->setParam('showCompact', true);
|
||||
|
||||
$this->setAttribute('data-icinga-url', $url);
|
||||
$this->setAttribute('data-icinga-dashlet', $this->getName());
|
||||
$dashletHtml->setAttribute('data-icinga-url', $url);
|
||||
$dashletHtml->setAttribute('data-icinga-dashlet', $this->getName());
|
||||
|
||||
$this->addHtml(new HtmlElement('h1', null, new Link(
|
||||
$dashletHtml->addHtml(new HtmlElement('h1', null, new Link(
|
||||
t($this->getTitle()),
|
||||
$url->getUrlWithout(['showCompact', 'limit'])->getRelativeUrl(),
|
||||
[
|
||||
@ -306,7 +176,7 @@ class Dashlet extends BaseHtmlElement
|
||||
]
|
||||
)));
|
||||
|
||||
$this->addHtml(HtmlElement::create(
|
||||
$dashletHtml->addHtml(HtmlElement::create(
|
||||
'p',
|
||||
['class' => 'progress-label'],
|
||||
[
|
||||
@ -317,18 +187,20 @@ class Dashlet extends BaseHtmlElement
|
||||
]
|
||||
));
|
||||
}
|
||||
|
||||
return $dashletHtml;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
public function toArray($stringify = true)
|
||||
{
|
||||
$pane = $this->getPane();
|
||||
return [
|
||||
'id' => $this->getUuid(),
|
||||
'pane' => $this->getPane() ? $this->getPane()->getName() : null,
|
||||
'name' => $this->getName(),
|
||||
'url' => $this->getUrl()->getRelativeUrl(),
|
||||
'label' => $this->getTitle(),
|
||||
'order' => $this->getPriority(),
|
||||
'disabled' => (int) $this->isDisabled(),
|
||||
'id' => $this->getUuid(),
|
||||
'pane' => ! $stringify ? $pane : ($pane ? $pane->getName() : null),
|
||||
'name' => $this->getName(),
|
||||
'url' => $this->getUrl()->getRelativeUrl(),
|
||||
'label' => $this->getTitle(),
|
||||
'order' => $this->getPriority(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -6,72 +6,64 @@ namespace Icinga\Web\Dashboard\ItemList;
|
||||
|
||||
use Icinga\Web\Dashboard\Common\ItemListControl;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\ActionLink;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
class DashboardHomeList extends ItemListControl
|
||||
{
|
||||
/** @var DashboardHome */
|
||||
protected $home;
|
||||
|
||||
protected $defaultAttributes = ['class' => 'home-list-control'];
|
||||
|
||||
public function __construct(DashboardHome $home)
|
||||
{
|
||||
$this->home = $home;
|
||||
$this->home->setActive();
|
||||
$this->home->loadPanesFromDB();
|
||||
$this->home->loadDashboardEntries();
|
||||
|
||||
$this->setCollapsibleControlClass('dashboard-list-info');
|
||||
$this->getAttributes()
|
||||
->registerAttributeCallback('class', function () {
|
||||
return 'home-list-control collapsible widget-sortable';
|
||||
})
|
||||
->registerAttributeCallback('data-toggle-element', function () {
|
||||
return '.dashboard-list-info';
|
||||
})
|
||||
->registerAttributeCallback('data-icinga-home', function () {
|
||||
return $this->home->getName();
|
||||
})
|
||||
->registerAttributeCallback('id', function () {
|
||||
return 'home_' . $this->home->getPriority();
|
||||
});
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
protected function getHtmlId()
|
||||
{
|
||||
// TODO: How should disabled homes look like?
|
||||
parent::assemble();
|
||||
return $this->home->getUuid();
|
||||
}
|
||||
|
||||
$header = HtmlElement::create('h1', ['class' => 'collapsible-header home'], $this->home->getLabel());
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/rename-home')->setParams([
|
||||
'home' => $this->home->getName()
|
||||
]);
|
||||
protected function getCollapsibleControlClass()
|
||||
{
|
||||
return 'dashboard-list-info';
|
||||
}
|
||||
|
||||
$header->addHtml(new Link(t('Edit'), $url, [
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
protected function createItemList()
|
||||
{
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/edit-home')
|
||||
->setParams(['home' => $this->home->getName()]);
|
||||
|
||||
$this->addHtml($header);
|
||||
$disable = $this->home->getName() === DashboardHome::DEFAULT_HOME;
|
||||
$this->assembleHeader($url, $this->home->getTitle(), $disable);
|
||||
|
||||
$list = HtmlElement::create('ul', ['class' => 'dashboard-item-list']);
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/new-dashlet');
|
||||
$url->setParams(['home' => $this->home->getName()]);
|
||||
|
||||
// List all dashboard panes
|
||||
foreach ($this->home->getPanes() as $pane) {
|
||||
foreach ($this->home->getEntries() as $pane) {
|
||||
$pane->setHome($this->home); // In case it's not set
|
||||
|
||||
$list->addHtml(new DashboardList($pane));
|
||||
}
|
||||
|
||||
$this->addHtml($list);
|
||||
$this->addHtml(new ActionLink(t('Add Dashboard'), $url, 'plus', [
|
||||
'class' => 'add-dashboard',
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function createActionLink()
|
||||
{
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/new-pane');
|
||||
$url->setParams(['home' => $this->home->getName()]);
|
||||
|
||||
return new ActionLink(t('Add Dashboard'), $url, 'plus', ['class' => 'add-dashboard']);
|
||||
}
|
||||
}
|
||||
|
@ -10,67 +10,65 @@ use Icinga\Web\Dashboard\Pane;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\ActionLink;
|
||||
use ipl\Web\Widget\Link;
|
||||
|
||||
class DashboardList extends ItemListControl
|
||||
{
|
||||
/** @var Pane */
|
||||
protected $pane;
|
||||
|
||||
protected $defaultAttributes = ['class' => 'dashboard-list-control'];
|
||||
|
||||
public function __construct(Pane $pane)
|
||||
{
|
||||
$this->pane = $pane;
|
||||
|
||||
$this->setCollapsibleControlClass('dashlets-list-info');
|
||||
$this->getAttributes()
|
||||
->registerAttributeCallback('class', function () {
|
||||
return 'dashboard-list-control collapsible widget-sortable';
|
||||
})
|
||||
->registerAttributeCallback('data-toggle-element', function () {
|
||||
return '.dashlets-list-info';
|
||||
})
|
||||
->registerAttributeCallback('data-icinga-pane', function () {
|
||||
return $this->pane->getHome()->getName() . '|' . $this->pane->getName();
|
||||
})
|
||||
->registerAttributeCallback('id', function () {
|
||||
return 'pane_' . $this->pane->getPriority();
|
||||
return $this->pane->getName();
|
||||
});
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
protected function getHtmlId()
|
||||
{
|
||||
// TODO: How should disabled dashboard panes look like?
|
||||
parent::assemble();
|
||||
return bin2hex($this->pane->getUuid());
|
||||
}
|
||||
|
||||
$header = HtmlElement::create('h1', ['class' => 'collapsible-header'], $this->pane->getTitle());
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/edit-pane')->setParams([
|
||||
'home' => $this->pane->getHome()->getName(),
|
||||
'pane' => $this->pane->getName()
|
||||
]);
|
||||
protected function getCollapsibleControlClass()
|
||||
{
|
||||
return 'dashlets-list-info';
|
||||
}
|
||||
|
||||
$header->addHtml(new Link(t('Edit'), $url, [
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
protected function createItemList()
|
||||
{
|
||||
$pane = $this->pane;
|
||||
$this->getAttributes()->set('data-toggle-element', '.dashlets-list-info');
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/edit-pane')
|
||||
->setParams(['home' => $pane->getHome()->getName(), 'pane' => $pane->getName()]);
|
||||
|
||||
$this->addHtml($header);
|
||||
$this->assembleHeader($url, $pane->getTitle());
|
||||
|
||||
$list = HtmlElement::create('ul', ['class' => 'dashlet-item-list']);
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/new-dashlet');
|
||||
$url->setParams([
|
||||
'home' => $this->pane->getHome(),
|
||||
'pane' => $this->pane->getName()
|
||||
'home' => $pane->getHome()->getName(),
|
||||
'pane' => $pane->getName()
|
||||
]);
|
||||
|
||||
foreach ($this->pane->getDashlets() as $dashlet) {
|
||||
foreach ($pane->getEntries() as $dashlet) {
|
||||
$list->addHtml(new DashletListItem($dashlet, true));
|
||||
}
|
||||
|
||||
$this->addHtml($list);
|
||||
$this->addHtml(new ActionLink(t('Add Dashlet'), $url, 'plus', [
|
||||
'class' => 'add-dashlet',
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
return $list;
|
||||
}
|
||||
|
||||
protected function createActionLink()
|
||||
{
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/new-dashlet');
|
||||
$url->setParams([
|
||||
'home' => $this->pane->getHome()->getName(),
|
||||
'pane' => $this->pane->getName()
|
||||
]);
|
||||
|
||||
return new ActionLink(t('Add Dashlet'), $url, 'plus', ['class' => 'add-dashlet']);
|
||||
}
|
||||
}
|
||||
|
@ -28,17 +28,13 @@ class DashletListItem extends BaseHtmlElement
|
||||
$this->dashlet = $dashlet;
|
||||
$this->renderEditButton = $renderEditButton;
|
||||
|
||||
if ($this->dashlet) {
|
||||
$this->getAttributes()
|
||||
->set('draggable', 'true')
|
||||
->add('class', 'widget-sortable');
|
||||
|
||||
if ($this->dashlet && $renderEditButton) {
|
||||
$this->getAttributes()
|
||||
->registerAttributeCallback('data-icinga-dashlet', function () {
|
||||
return $this->dashlet->getName();
|
||||
})
|
||||
->registerAttributeCallback('id', function () {
|
||||
return 'dashlet_' . $this->dashlet->getPriority();
|
||||
return bin2hex($this->dashlet->getUuid());
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -63,23 +59,33 @@ class DashletListItem extends BaseHtmlElement
|
||||
|
||||
if (! $this->dashlet) {
|
||||
$title->add(t('Custom Url'));
|
||||
} elseif ($this->renderEditButton) {
|
||||
$title->addHtml(new Link(
|
||||
t($this->dashlet->getTitle()),
|
||||
$this->dashlet->getUrl()->getUrlWithout(['showCompact', 'limit'])->getRelativeUrl(),
|
||||
[
|
||||
'class' => 'dashlet-title',
|
||||
'aria-label' => t($this->dashlet->getTitle()),
|
||||
'title' => t($this->dashlet->getTitle()),
|
||||
'data-base-target' => '_next'
|
||||
]
|
||||
));
|
||||
|
||||
$pane = $this->dashlet->getPane();
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/edit-dashlet');
|
||||
$url->setParams([
|
||||
'home' => $pane->getHome()->getName(),
|
||||
'pane' => $pane->getName(),
|
||||
'dashlet' => $this->dashlet->getName()
|
||||
]);
|
||||
|
||||
$title->addHtml(new Link(t('Edit'), $url, [
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
} else {
|
||||
$title->add($this->dashlet->getTitle());
|
||||
|
||||
if ($this->renderEditButton) {
|
||||
$pane = $this->dashlet->getPane();
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/edit-dashlet');
|
||||
$url->setParams([
|
||||
'home' => $pane->getHome()->getName(),
|
||||
'pane' => $pane->getName(),
|
||||
'dashlet' => $this->dashlet->getName()
|
||||
]);
|
||||
|
||||
$title->addHtml(new Link(t('Edit'), $url, [
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
}
|
||||
$title->getAttributes()->set('title', $this->dashlet->getTitle());
|
||||
}
|
||||
|
||||
return $title;
|
||||
@ -92,7 +98,12 @@ class DashletListItem extends BaseHtmlElement
|
||||
if (! $this->dashlet) {
|
||||
$section->add(t('Create a dashlet with custom url and filter'));
|
||||
} else {
|
||||
$section->add($this->dashlet->getDescription() ?: $this->dashlet->getTitle());
|
||||
$section->getAttributes()->set(
|
||||
'title',
|
||||
$this->dashlet->getDescription() ?: t('There is no provided description.')
|
||||
);
|
||||
|
||||
$section->add($this->dashlet->getDescription() ?: t('There is no provided dashlet description.'));
|
||||
}
|
||||
|
||||
return $section;
|
||||
|
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Dashboard\ItemList;
|
||||
|
||||
use ipl\Html\Contract\FormElement;
|
||||
|
@ -4,142 +4,54 @@
|
||||
|
||||
namespace Icinga\Web\Dashboard;
|
||||
|
||||
use Icinga\Common\DataExtractor;
|
||||
use Icinga\Web\Dashboard\Common\DisableWidget;
|
||||
use Icinga\Web\Dashboard\Common\OrderWidget;
|
||||
use Icinga\Web\Dashboard\Common\BaseDashboard;
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Exception\ConfigurationError;
|
||||
use Icinga\Model;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\Common\DashboardControls;
|
||||
use Icinga\Web\Dashboard\Common\OverridingWidget;
|
||||
use Icinga\Web\Dashboard\Common\Sortable;
|
||||
use ipl\Stdlib\Filter;
|
||||
use ipl\Web\Url;
|
||||
|
||||
use function ipl\Stdlib\get_php_type;
|
||||
|
||||
/**
|
||||
* A pane, displaying different Dashboard dashlets
|
||||
*/
|
||||
class Pane implements OverridingWidget
|
||||
class Pane extends BaseDashboard implements Sortable, OverridingWidget
|
||||
{
|
||||
use DisableWidget;
|
||||
use OrderWidget;
|
||||
use DataExtractor;
|
||||
use DashboardControls;
|
||||
|
||||
const TABLE = 'dashboard';
|
||||
|
||||
/**
|
||||
* The name of this pane
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* The title of this pane, as displayed in the dashboard tabs
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $title;
|
||||
|
||||
/**
|
||||
* An array of @see Dashlet that are displayed in this pane
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $dashlets = [];
|
||||
protected $dashlets = [];
|
||||
|
||||
/**
|
||||
* Whether this widget overrides another widget
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $override;
|
||||
|
||||
/**
|
||||
* Unique identifier of this pane
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $uuid;
|
||||
|
||||
/**
|
||||
* Name of the owner/creator of this pane
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $owner;
|
||||
protected $override;
|
||||
|
||||
/**
|
||||
* Number of users who have subscribed to this pane if (public)
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $acceptance;
|
||||
protected $acceptance;
|
||||
|
||||
/**
|
||||
* A dashboard home this pane is a part of
|
||||
*
|
||||
* @var DashboardHome
|
||||
*/
|
||||
private $home;
|
||||
|
||||
/**
|
||||
* Create a new pane
|
||||
*
|
||||
* @param string $name The pane to create
|
||||
* @param array $properties
|
||||
*/
|
||||
public function __construct($name, array $properties = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->title = $name;
|
||||
|
||||
if (! empty($properties)) {
|
||||
$this->fromArray($properties);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this pane
|
||||
*
|
||||
* @param string $name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this pane
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the title of this pane
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTitle()
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite the title of this pane
|
||||
*
|
||||
* @param string $title The new title to use for this pane
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setTitle($title)
|
||||
{
|
||||
$this->title = $title;
|
||||
|
||||
return $this;
|
||||
}
|
||||
protected $home;
|
||||
|
||||
public function override(bool $override)
|
||||
{
|
||||
@ -153,54 +65,6 @@ class Pane implements OverridingWidget
|
||||
return $this->override;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this pane's unique identifier
|
||||
*
|
||||
* @param string $uuid
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUuid($uuid)
|
||||
{
|
||||
$this->uuid = $uuid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this pane's unique identifier
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getUuid()
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the owner of this dashboard
|
||||
*
|
||||
* @param string $owner
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOwner($owner)
|
||||
{
|
||||
$this->owner = $owner;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get owner of this dashboard
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOwner()
|
||||
{
|
||||
return $this->owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of users who have subscribed to this pane if (public)
|
||||
*
|
||||
@ -249,86 +113,12 @@ class Pane implements OverridingWidget
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if a dashlet with the given name exists in this pane
|
||||
*
|
||||
* @param string $name The title of the dashlet to check for existence
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDashlet($name)
|
||||
{
|
||||
return array_key_exists($name, $this->dashlets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current pane has any dashlets
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasDashlets()
|
||||
{
|
||||
return ! empty($this->dashlets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dashlet with the given name if existing
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Dashlet
|
||||
*/
|
||||
public function getDashlet($name)
|
||||
{
|
||||
if ($this->hasDashlet($name)) {
|
||||
return $this->dashlets[$name];
|
||||
}
|
||||
|
||||
throw new ProgrammingError('Trying to access invalid dashlet: %s', $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dashlets belongs to this pane
|
||||
*
|
||||
* @return Dashlet[]
|
||||
*/
|
||||
public function getDashlets()
|
||||
{
|
||||
uasort($this->dashlets, function (Dashlet $x, Dashlet $y) {
|
||||
return $x->getPriority() - $y->getPriority();
|
||||
});
|
||||
|
||||
return $this->dashlets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dashlets of this pane
|
||||
*
|
||||
* @param Dashlet[] $dashlets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDashlets(array $dashlets)
|
||||
{
|
||||
$this->dashlets = $dashlets;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create, add and return a new dashlet
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $url
|
||||
*
|
||||
* @return Dashlet
|
||||
*/
|
||||
public function createDashlet($name, $url = null)
|
||||
public function createEntry($name, $url = null)
|
||||
{
|
||||
$dashlet = new Dashlet($name, $url, $this);
|
||||
$this->addDashlet($dashlet);
|
||||
|
||||
return $dashlet;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -343,9 +133,9 @@ class Pane implements OverridingWidget
|
||||
public function addDashlet($dashlet, $url = null)
|
||||
{
|
||||
if ($dashlet instanceof Dashlet) {
|
||||
$this->dashlets[$dashlet->getName()] = $dashlet;
|
||||
$this->addEntry($dashlet);
|
||||
} elseif (is_string($dashlet) && $url !== null) {
|
||||
$this->createDashlet($dashlet, $url);
|
||||
$this->createEntry($dashlet, $url);
|
||||
} else {
|
||||
throw new ConfigurationError('Invalid dashlet added: %s', $dashlet);
|
||||
}
|
||||
@ -364,31 +154,24 @@ class Pane implements OverridingWidget
|
||||
*/
|
||||
public function add($name, $url, $priority = 0, $description = null)
|
||||
{
|
||||
$dashlet = $this->createDashlet($name, $url);
|
||||
$this->createEntry($name, $url);
|
||||
$dashlet = $this->getEntry($name);
|
||||
$dashlet
|
||||
->setDescription($description)
|
||||
->setPriority($priority);
|
||||
$this->addDashlet($dashlet);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given dashlet if it exists in this pane
|
||||
*
|
||||
* @param Dashlet|string $dashlet
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeDashlet($dashlet)
|
||||
public function removeEntry($dashlet)
|
||||
{
|
||||
$name = $dashlet instanceof Dashlet ? $dashlet->getName() : $dashlet;
|
||||
if (! $this->hasDashlet($name)) {
|
||||
if (! $this->hasEntry($name)) {
|
||||
throw new ProgrammingError('Trying to remove invalid dashlet: %s', $name);
|
||||
}
|
||||
|
||||
if (! $dashlet instanceof Dashlet) {
|
||||
$dashlet = $this->getDashlet($dashlet);
|
||||
$dashlet = $this->getEntry($dashlet);
|
||||
}
|
||||
|
||||
Dashboard::getConn()->delete(Dashlet::TABLE, [
|
||||
@ -399,38 +182,12 @@ class Pane implements OverridingWidget
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all or a given list of dashlets from this pane
|
||||
*
|
||||
* @param array $dashlets Optional list of dashlets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeDashlets(array $dashlets = [])
|
||||
public function loadDashboardEntries($name = '')
|
||||
{
|
||||
$dashlets = ! empty($dashlets) ? $dashlets : $this->getDashlets();
|
||||
foreach ($dashlets as $dashlet) {
|
||||
$this->removeDashlet($dashlet);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all dashlets this dashboard is assigned to
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loadDashletsFromDB()
|
||||
{
|
||||
if ($this->isDisabled()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->dashlets = [];
|
||||
$dashlets = Model\Dashlet::on(Dashboard::getConn())->with('module_dashlet');
|
||||
$dashlets->filter(Filter::equal('dashboard_id', $this->getUuid()));
|
||||
|
||||
$this->setEntries([]);
|
||||
foreach ($dashlets as $dashlet) {
|
||||
$newDashlet = new Dashlet($dashlet->name, $dashlet->url, $this);
|
||||
$newDashlet->fromArray([
|
||||
@ -447,44 +204,40 @@ class Pane implements OverridingWidget
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the given dashlet(s)
|
||||
*
|
||||
* If you want to move the dashlet(s) from another to this pane,
|
||||
* you have to also pass the origin pane
|
||||
*
|
||||
* @param Dashlet|Dashlet[] $dashlets
|
||||
* @param ?Pane $origin
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function manageDashlets($dashlets, Pane $origin = null)
|
||||
public function manageEntry($entry, BaseDashboard $origin = null, $updateChildEntries = false)
|
||||
{
|
||||
if ($origin && ! $origin instanceof Pane) {
|
||||
throw new \InvalidArgumentException(sprintf(
|
||||
__METHOD__ . ' expects parameter "$origin" to be an instance of "%s". Got "%s" instead.',
|
||||
get_php_type($this),
|
||||
get_php_type($origin)
|
||||
));
|
||||
}
|
||||
|
||||
if (! $this->getHome()) {
|
||||
throw new \LogicException(
|
||||
'Dashlets cannot be managed. Please make sure to set the current dashboard home beforehand.'
|
||||
);
|
||||
}
|
||||
|
||||
$user = Dashboard::getUser();
|
||||
$home = $this->getHome();
|
||||
$user = Dashboard::getUser()->getUsername();
|
||||
$conn = Dashboard::getConn();
|
||||
$dashlets = is_array($dashlets) ? $dashlets : [$dashlets];
|
||||
$order = count($this->getDashlets()) + 1;
|
||||
|
||||
$dashlets = is_array($entry) ? $entry : [$entry];
|
||||
// highest priority is 0, so count($entries) are all always lowest prio + 1
|
||||
$order = count($this->getEntries());
|
||||
foreach ($dashlets as $dashlet) {
|
||||
if (is_array($dashlet)) {
|
||||
$this->manageDashlets($dashlet, $origin);
|
||||
$this->manageEntry($dashlet, $origin);
|
||||
}
|
||||
|
||||
if (! $dashlet instanceof Dashlet) {
|
||||
break;
|
||||
}
|
||||
|
||||
$uuid = Dashboard::getSHA1(
|
||||
$user->getUsername() . $this->getHome()->getName() . $this->getName() . $dashlet->getName()
|
||||
);
|
||||
|
||||
if (! $this->hasDashlet($dashlet->getName()) && (! $origin || ! $origin->hasDashlet($dashlet->getName()))) {
|
||||
$uuid = Dashboard::getSHA1($user . $home->getName() . $this->getName() . $dashlet->getName());
|
||||
if (! $this->hasEntry($dashlet->getName()) && (! $origin || ! $origin->hasEntry($dashlet->getName()))) {
|
||||
$conn->insert(Dashlet::TABLE, [
|
||||
'id' => $uuid,
|
||||
'dashboard_id' => $this->getUuid(),
|
||||
@ -495,22 +248,41 @@ class Pane implements OverridingWidget
|
||||
]);
|
||||
|
||||
if ($dashlet->isModuleDashlet()) {
|
||||
$systemUuid = Dashboard::getSHA1($dashlet->getModule() . $this->getName() . $dashlet->getName());
|
||||
$conn->insert('dashlet_system', [
|
||||
'dashlet_id' => $uuid,
|
||||
'module_dashlet_id' => $systemUuid
|
||||
]);
|
||||
$systemUuid = $dashlet->getUuid();
|
||||
if (! $systemUuid && $dashlet->getPane()) {
|
||||
$systemUuid = Dashboard::getSHA1(
|
||||
$dashlet->getModule() . $dashlet->getPane()->getName() . $dashlet->getName()
|
||||
);
|
||||
}
|
||||
|
||||
if ($systemUuid) {
|
||||
$conn->insert('dashlet_system', [
|
||||
'dashlet_id' => $uuid,
|
||||
'module_dashlet_id' => $systemUuid
|
||||
]);
|
||||
}
|
||||
}
|
||||
} elseif (! $this->hasDashlet($dashlet->getName())
|
||||
|| ! $origin
|
||||
|| ! $origin->hasDashlet($dashlet->getName())) {
|
||||
} elseif (! $this->hasEntry($dashlet->getName()) || ! $origin
|
||||
|| ! $origin->hasEntry($dashlet->getName())) {
|
||||
$filterCondition = [
|
||||
'id = ?' => $dashlet->getUuid(),
|
||||
'dashboard_id = ?' => $this->getUuid()
|
||||
];
|
||||
|
||||
if ($origin && $origin->hasEntry($dashlet->getName())) {
|
||||
$filterCondition = [
|
||||
'id = ?' => $origin->getEntry($dashlet->getName())->getUuid(),
|
||||
'dashboard_id = ?' => $origin->getUuid()
|
||||
];
|
||||
}
|
||||
|
||||
$conn->update(Dashlet::TABLE, [
|
||||
'id' => $uuid,
|
||||
'dashboard_id' => $this->getUuid(),
|
||||
'label' => $dashlet->getTitle(),
|
||||
'url' => $dashlet->getUrl()->getRelativeUrl(),
|
||||
'priority' => $dashlet->getPriority()
|
||||
], ['id = ?' => $dashlet->getUuid()]);
|
||||
], $filterCondition);
|
||||
} else {
|
||||
// This should have already been handled by the caller
|
||||
break;
|
||||
@ -522,15 +294,15 @@ class Pane implements OverridingWidget
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
public function toArray($stringify = true)
|
||||
{
|
||||
$home = $this->getHome();
|
||||
return [
|
||||
'id' => $this->getUuid(),
|
||||
'name' => $this->getName(),
|
||||
'label' => $this->getTitle(),
|
||||
'home' => $this->getHome() ? $this->getHome()->getName() : null,
|
||||
'home' => ! $stringify ? $home : ($home ? $home->getName() : null),
|
||||
'priority' => $this->getPriority(),
|
||||
'disabled' => (int) $this->isDisabled()
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ namespace Icinga\Web\Dashboard;
|
||||
|
||||
use Icinga\Web\Dashboard\ItemList\DashboardHomeList;
|
||||
use Icinga\Web\Dashboard\ItemList\DashboardList;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use ipl\Html\BaseHtmlElement;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\ActionLink;
|
||||
@ -27,31 +26,25 @@ class Settings extends BaseHtmlElement
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
// TODO: What we should do with disabled homes??
|
||||
$activeHome = $this->dashboard->getActiveHome();
|
||||
|
||||
if (empty($this->dashboard->getHomes())) {
|
||||
// TODO: No dashboard homes :( what should we render now??
|
||||
} elseif (count($this->dashboard->getHomes()) === 1 && $activeHome->getName() === DashboardHome::DEFAULT_HOME) {
|
||||
foreach ($activeHome->getPanes() as $pane) {
|
||||
if (count($this->dashboard->getEntries()) === 1 && $activeHome->getName() === DashboardHome::DEFAULT_HOME) {
|
||||
foreach ($activeHome->getEntries() as $pane) {
|
||||
$pane->setHome($activeHome);
|
||||
|
||||
$this->addHtml(new DashboardList($pane));
|
||||
}
|
||||
|
||||
$this->addHtml(new ActionLink(
|
||||
t('Add Dashboard'),
|
||||
Url::fromPath(Dashboard::BASE_ROUTE . '/new-dashlet'),
|
||||
'plus',
|
||||
[
|
||||
'class' => 'add-dashboard',
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]
|
||||
));
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/new-pane')
|
||||
->setParams(['home' => $activeHome->getName()]);
|
||||
|
||||
$this->addHtml(new ActionLink(t('Add Dashboard'), $url, 'plus', [
|
||||
'class' => 'add-dashboard',
|
||||
'data-icinga-modal' => true,
|
||||
'data-no-icinga-ajax' => true
|
||||
]));
|
||||
} else {
|
||||
// Make a list of dashboard homes
|
||||
foreach ($this->dashboard->getHomes() as $home) {
|
||||
foreach ($this->dashboard->getEntries() as $home) {
|
||||
$this->addHtml(new DashboardHomeList($home));
|
||||
}
|
||||
}
|
||||
|
@ -4,29 +4,26 @@
|
||||
|
||||
namespace Icinga\Web\Dashboard\Setup;
|
||||
|
||||
use Icinga\Forms\Dashboard\BaseDashboardForm;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Dashboard\Dashlet;
|
||||
use Icinga\Web\Dashboard\Pane;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Notification;
|
||||
use Icinga\Web\Dashboard\ItemList\DashletListMultiSelect;
|
||||
use ipl\Html\HtmlElement;
|
||||
use ipl\Html\ValidHtml;
|
||||
use ipl\Web\Compat\CompatForm;
|
||||
use ipl\Web\Url;
|
||||
use ipl\Web\Widget\Icon;
|
||||
|
||||
class SetupNewDashboard extends CompatForm
|
||||
class SetupNewDashboard extends BaseDashboardForm
|
||||
{
|
||||
/** @var Dashboard */
|
||||
protected $dashboard;
|
||||
|
||||
/** @var array Module dashlets from the DB */
|
||||
private $dashlets = [];
|
||||
|
||||
public function __construct(Dashboard $dashboard)
|
||||
{
|
||||
$this->dashboard = $dashboard;
|
||||
parent::__construct($dashboard);
|
||||
|
||||
$this->setRedirectUrl((string) Url::fromPath(Dashboard::BASE_ROUTE));
|
||||
$this->setAction($this->getRedirectUrl() . '/setup-dashboard');
|
||||
@ -46,13 +43,6 @@ class SetupNewDashboard extends CompatForm
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasBeenSubmitted()
|
||||
{
|
||||
return $this->hasBeenSent()
|
||||
&& ($this->getPopulatedValue('btn_cancel')
|
||||
|| $this->getPopulatedValue('submit'));
|
||||
}
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
$this->getAttributes()->add('class', 'modal-form');
|
||||
@ -60,6 +50,7 @@ class SetupNewDashboard extends CompatForm
|
||||
if ($this->getPopulatedValue('btn_next')) { // Configure Dashlets
|
||||
$this->dumpArbitaryDashlets();
|
||||
|
||||
$submitButtonLabel = t('Add Dashlets');
|
||||
$this->addElement('text', 'pane', [
|
||||
'required' => true,
|
||||
'label' => t('Dashboard Title'),
|
||||
@ -134,10 +125,8 @@ class SetupNewDashboard extends CompatForm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$submitButton = $this->createElement('submit', 'submit', ['label' => t('Add Dashlets')]);
|
||||
$this->registerElement($submitButton)->decorate($submitButton);
|
||||
} else { // Select Dashlets
|
||||
$submitButtonLabel = t('Next');
|
||||
$list = HtmlElement::create('ul', ['class' => 'dashlet-item-list empty-list']);
|
||||
$multi = new DashletListMultiSelect();
|
||||
$multi->setCheckBox($this->createElement('checkbox', 'custom_url', ['class' => 'sr-only']));
|
||||
@ -169,16 +158,19 @@ class SetupNewDashboard extends CompatForm
|
||||
|
||||
$this->addHtml($listControl->addHtml($list));
|
||||
}
|
||||
|
||||
$submitButton = $this->createElement('submit', 'btn_next', [
|
||||
'class' => 'autosubmit',
|
||||
'label' => t('Next'),
|
||||
]);
|
||||
$this->registerElement($submitButton)->decorate($submitButton);
|
||||
}
|
||||
|
||||
$this->addElement('submit', 'btn_cancel', ['label' => t('Cancel')]);
|
||||
$this->getElement('btn_cancel')->setWrapper($submitButton->getWrapper());
|
||||
$submitButton = $this->registerSubmitButton($submitButtonLabel);
|
||||
if (! $this->getPopulatedValue('btn_next')) {
|
||||
$submitButton
|
||||
->setName('btn_next')
|
||||
->getAttributes()->add('class', 'autosubmit');
|
||||
}
|
||||
|
||||
$formControls = $this->createFormControls();
|
||||
$formControls->add([$submitButton, $this->createCancelButton()]);
|
||||
|
||||
$this->addHtml($formControls);
|
||||
}
|
||||
|
||||
protected function onSuccess()
|
||||
@ -190,12 +182,12 @@ class SetupNewDashboard extends CompatForm
|
||||
$conn->beginTransaction();
|
||||
|
||||
try {
|
||||
$this->dashboard->getHome(DashboardHome::DEFAULT_HOME)->managePanes($pane);
|
||||
$this->dashboard->getEntry(DashboardHome::DEFAULT_HOME)->manageEntry($pane);
|
||||
|
||||
// If element name "dashlet" and "url" are set we need to only store one dashlet
|
||||
if (($name = $this->getPopulatedValue('dashlet')) && ($url = $this->getPopulatedValue('url'))) {
|
||||
$dashlet = new Dashlet($name, $url, $pane);
|
||||
$pane->manageDashlets($dashlet);
|
||||
$pane->manageEntry($dashlet);
|
||||
} else {
|
||||
foreach ($this->dashlets as $module => $dashlets) {
|
||||
$moduleDashlets = [];
|
||||
@ -226,7 +218,7 @@ class SetupNewDashboard extends CompatForm
|
||||
$moduleDashlets[$dashlet->getName()] = $dashlet;
|
||||
}
|
||||
|
||||
$pane->manageDashlets($moduleDashlets);
|
||||
$pane->manageEntry($moduleDashlets);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web;
|
||||
|
||||
use Icinga\Model\Home;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Navigation\DashboardHomeItem;
|
||||
use ipl\Stdlib\Filter;
|
||||
|
||||
/**
|
||||
@ -28,7 +31,7 @@ class HomeMenu extends Menu
|
||||
$homes->filter(Filter::equal('username', $user->getUsername()));
|
||||
|
||||
foreach ($homes as $home) {
|
||||
$dashboardHome = new DashboardHome($home->name, [
|
||||
$dashboardHome = new DashboardHomeItem($home->name, [
|
||||
'uuid' => $home->id,
|
||||
'label' => t($home->label),
|
||||
'priority' => $home->priority,
|
||||
@ -38,4 +41,26 @@ class HomeMenu extends Menu
|
||||
$dashboardItem->addChild($dashboardHome);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load dashboard homes form the navigation menu
|
||||
*
|
||||
* @return DashboardHome[]
|
||||
*/
|
||||
public function loadHomes()
|
||||
{
|
||||
$homes = [];
|
||||
foreach ($this->getItem('dashboard')->getChildren() as $child) {
|
||||
if (! $child instanceof DashboardHomeItem) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$home = DashboardHome::create($child);
|
||||
$home->setTitle($child->getLabel());
|
||||
|
||||
$homes[$child->getName()] = $home;
|
||||
}
|
||||
|
||||
return $homes;
|
||||
}
|
||||
}
|
||||
|
@ -1,414 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Navigation;
|
||||
|
||||
use Icinga\Exception\ProgrammingError;
|
||||
use Icinga\Web\Dashboard\Common\DisableWidget;
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Dashboard\Pane;
|
||||
use Icinga\Model;
|
||||
use ipl\Stdlib\Filter;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class DashboardHome extends NavigationItem
|
||||
{
|
||||
use DisableWidget;
|
||||
|
||||
/**
|
||||
* Name of the default home
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const DEFAULT_HOME = 'Default Home';
|
||||
|
||||
/**
|
||||
* Database table name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const TABLE = 'dashboard_home';
|
||||
|
||||
/**
|
||||
* A list of @see Pane assigned to this dashboard home
|
||||
*
|
||||
* @var Pane[]
|
||||
*/
|
||||
private $panes = [];
|
||||
|
||||
/**
|
||||
* This home's unique identifier
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $uuid;
|
||||
|
||||
/**
|
||||
* A type of this dashboard home
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $type = Dashboard::SYSTEM;
|
||||
|
||||
/**
|
||||
* Init this dashboard home
|
||||
*
|
||||
* Doesn't set the url of this dashboard home if it's the default one or is disabled
|
||||
* to prevent from being rendered as dropdown in the navigation bar
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->getName() !== self::DEFAULT_HOME && ! $this->isDisabled()) {
|
||||
$this->setUrl(Url::fromPath(Dashboard::BASE_ROUTE . '/home', [
|
||||
'home' => $this->getName()
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this dashboard home's url
|
||||
*
|
||||
* Parent class would always report a default url if $this->url isn't
|
||||
* set, which we do it on purpose.
|
||||
*
|
||||
* @return \Icinga\Web\Url
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this home has been activated
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getActive()
|
||||
{
|
||||
return $this->active;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this home is active
|
||||
*
|
||||
* DB dashboard will load only when this home has been activated
|
||||
*
|
||||
* @param bool $active
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setActive($active = true)
|
||||
{
|
||||
$this->active = $active;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of this dashboard home
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this dashboard home
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the uuid of this dashboard home
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getUuid()
|
||||
{
|
||||
return $this->uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the uuid of this dashboard home
|
||||
*
|
||||
* @param int $uuid
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setUuid(int $uuid)
|
||||
{
|
||||
$this->uuid = $uuid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a pane with the given name if exists
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return Pane
|
||||
*/
|
||||
public function getPane($name)
|
||||
{
|
||||
if (! $this->hasPane($name)) {
|
||||
throw new ProgrammingError('Trying to retrieve invalid dashboard pane "%s"', $name);
|
||||
}
|
||||
|
||||
return $this->panes[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether this home has any dashboard panes
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPanes()
|
||||
{
|
||||
return ! empty($this->panes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether the given pane exist
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPane($name)
|
||||
{
|
||||
return array_key_exists($name, $this->panes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all dashboards of this home
|
||||
*
|
||||
* @param bool $skipDisabled Whether to skip disabled dashboards
|
||||
*
|
||||
* @return Pane[]
|
||||
*/
|
||||
public function getPanes($skipDisabled = false)
|
||||
{
|
||||
// As the panes can also be added individually afterwards, it might be the case that the priority
|
||||
// order gets mixed up, so we have to sort things here before being able to render them
|
||||
uasort($this->panes, function (Pane $x, Pane $y) {
|
||||
return $x->getPriority() - $y->getPriority();
|
||||
});
|
||||
|
||||
return ! $skipDisabled ? $this->panes : array_filter($this->panes, function ($pane) {
|
||||
return ! $pane->isDisabled();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set dashboards of this home
|
||||
*
|
||||
* @param Pane|Pane[] $panes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPanes($panes)
|
||||
{
|
||||
if ($panes instanceof Pane) {
|
||||
$panes = [$panes->getName() => $panes];
|
||||
}
|
||||
|
||||
$this->panes = $panes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new dashboard pane to this home
|
||||
*
|
||||
* @param Pane|string $pane
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addPane($pane)
|
||||
{
|
||||
if (! $pane instanceof Pane) {
|
||||
$pane = new Pane($pane);
|
||||
$pane
|
||||
->setHome($this)
|
||||
->setTitle($pane->getName());
|
||||
}
|
||||
|
||||
$this->panes[$pane->getName()] = $pane;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array with pane name=>title format
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPaneKeyTitleArr()
|
||||
{
|
||||
$panes = [];
|
||||
foreach ($this->getPanes(true) as $pane) {
|
||||
$panes[$pane->getName()] = $pane->getName();
|
||||
}
|
||||
|
||||
return $panes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given pane from this home
|
||||
*
|
||||
* @param Pane|string $pane
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removePane($pane)
|
||||
{
|
||||
$name = $pane instanceof Pane ? $pane->getName() : $pane;
|
||||
if (! $this->hasPane($name)) {
|
||||
throw new ProgrammingError('Trying to remove invalid dashboard pane "%s"', $name);
|
||||
}
|
||||
|
||||
$pane = $pane instanceof Pane ? $pane : $this->getPane($pane);
|
||||
if (! $pane->isOverriding()) {
|
||||
$pane->removeDashlets();
|
||||
|
||||
Dashboard::getConn()->delete(Pane::TABLE, [
|
||||
'id = ?' => $pane->getUuid(),
|
||||
'home_id = ?' => $this->getUuid()
|
||||
]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all/the given dashboard panes from this home
|
||||
*
|
||||
* @param Pane[] $panes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removePanes(array $panes = [])
|
||||
{
|
||||
$panes = ! empty($panes) ? $panes : $this->getPanes();
|
||||
foreach ($panes as $pane) {
|
||||
$this->removePane($pane);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all dashboards this user is assigned to from the DB
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function loadPanesFromDB()
|
||||
{
|
||||
// Skip when this home is either disabled or inactive
|
||||
if (! $this->getActive() || $this->isDisabled()) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->panes = [];
|
||||
$panes = Model\Pane::on(Dashboard::getConn())->utilize('home');
|
||||
$panes
|
||||
->filter(Filter::equal('home_id', $this->getUuid()))
|
||||
->filter(Filter::equal('username', Dashboard::getUser()->getUsername()));
|
||||
|
||||
foreach ($panes as $pane) {
|
||||
$newPane = new Pane($pane->name);
|
||||
//$newPane->disable($pane->disable);
|
||||
$newPane->fromArray([
|
||||
'uuid' => $pane->id,
|
||||
'title' => $pane->label,
|
||||
'priority' => $pane->priority,
|
||||
'home' => $this
|
||||
]);
|
||||
|
||||
$newPane->loadDashletsFromDB();
|
||||
|
||||
$this->panes[$newPane->getName()] = $newPane;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage the given pane(s)
|
||||
*
|
||||
* If you want to move the pane(s) from another to this home,
|
||||
* you have to also pass through the origin home with
|
||||
*
|
||||
* @param Pane|Pane[] $panes
|
||||
* @param ?DashboardHome $origin
|
||||
* @param bool $mngPaneDashlets
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function managePanes($panes, DashboardHome $origin = null, $mngPaneDashlets = false)
|
||||
{
|
||||
$user = Dashboard::getUser();
|
||||
$conn = Dashboard::getConn();
|
||||
|
||||
$panes = is_array($panes) ? $panes : [$panes];
|
||||
$order = count($this->getPanes()) + 1;
|
||||
|
||||
foreach ($panes as $pane) {
|
||||
$uuid = Dashboard::getSHA1($user->getUsername() . $this->getName() . $pane->getName());
|
||||
if (! $pane->isOverriding()) {
|
||||
if (! $this->hasPane($pane->getName()) && (! $origin || ! $origin->hasPane($pane->getName()))) {
|
||||
$conn->insert(Pane::TABLE, [
|
||||
'id' => $uuid,
|
||||
'home_id' => $this->getUuid(),
|
||||
'name' => $pane->getName(),
|
||||
'label' => $pane->getTitle(),
|
||||
'username' => $user->getUsername(),
|
||||
'priority' => $order++
|
||||
]);
|
||||
} elseif (! $this->hasPane($pane->getName()) || ! $origin || ! $origin->hasPane($pane->getName())) {
|
||||
$conn->update(Pane::TABLE, [
|
||||
'id' => $uuid,
|
||||
'home_id' => $this->getUuid(),
|
||||
'label' => $pane->getTitle(),
|
||||
'priority' => $pane->getPriority()
|
||||
], [
|
||||
'id = ?' => $pane->getUuid(),
|
||||
'home_id = ?' => $this->getUuid()
|
||||
]);
|
||||
} else {
|
||||
// Failed to move the pane! Should have been handled already by the caller
|
||||
break;
|
||||
}
|
||||
|
||||
$pane->setUuid($uuid);
|
||||
} else {
|
||||
// TODO(TBD)
|
||||
}
|
||||
|
||||
$pane->setHome($this);
|
||||
if ($mngPaneDashlets) {
|
||||
// Those dashboard panes are usually system defaults and go up when
|
||||
// the user is clicking on the "Use System Defaults" button
|
||||
$dashlets = $pane->getDashlets();
|
||||
$pane->setDashlets([]);
|
||||
$pane->manageDashlets($dashlets);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
42
library/Icinga/Web/Navigation/DashboardHomeItem.php
Normal file
42
library/Icinga/Web/Navigation/DashboardHomeItem.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/* Icinga Web 2 | (c) 2022 Icinga GmbH | GPLv2+ */
|
||||
|
||||
namespace Icinga\Web\Navigation;
|
||||
|
||||
use Icinga\Web\Dashboard\Dashboard;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use ipl\Web\Url;
|
||||
|
||||
class DashboardHomeItem extends NavigationItem
|
||||
{
|
||||
/**
|
||||
* Init this dashboard home
|
||||
*
|
||||
* Doesn't set the url of this dashboard home if it's the default one
|
||||
* to prevent from being rendered as dropdown in the navigation bar
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
if ($this->getName() !== DashboardHome::DEFAULT_HOME) {
|
||||
$this->setUrl(Url::fromPath(Dashboard::BASE_ROUTE . '/home', [
|
||||
'home' => $this->getName()
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this dashboard home's url
|
||||
*
|
||||
* Parent class would always report a default url if $this->url isn't
|
||||
* set, which we do it on purpose.
|
||||
*
|
||||
* @return \Icinga\Web\Url
|
||||
*/
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ namespace Icinga\Web\Widget;
|
||||
|
||||
use Icinga\Exception\Http\HttpNotFoundException;
|
||||
use Icinga\Application\Icinga;
|
||||
use Icinga\Web\Navigation\DashboardHome;
|
||||
use Icinga\Web\Dashboard\DashboardHome;
|
||||
use Icinga\Web\Url;
|
||||
|
||||
/**
|
||||
@ -37,7 +37,6 @@ class SearchDashboard extends \Icinga\Web\Dashboard\Dashboard
|
||||
public function __construct()
|
||||
{
|
||||
$this->searchHome = new DashboardHome(self::SEARCH_HOME);
|
||||
$this->searchHome->setActive();
|
||||
}
|
||||
|
||||
public function getTabs()
|
||||
@ -72,7 +71,8 @@ class SearchDashboard extends \Icinga\Web\Dashboard\Dashboard
|
||||
*/
|
||||
public function search($searchString = '')
|
||||
{
|
||||
$pane = $this->searchHome->addPane(self::SEARCH_PANE)->getPane(self::SEARCH_PANE)->setTitle(t('Search'));
|
||||
$pane = $this->searchHome->createEntry(self::SEARCH_PANE)->getEntry(self::SEARCH_PANE);
|
||||
$pane->setTitle(t('Search'));
|
||||
$this->activate(self::SEARCH_PANE);
|
||||
|
||||
$manager = Icinga::app()->getModuleManager();
|
||||
@ -83,7 +83,7 @@ class SearchDashboard extends \Icinga\Web\Dashboard\Dashboard
|
||||
$moduleSearchUrls = $module->getSearchUrls();
|
||||
if (! empty($moduleSearchUrls)) {
|
||||
if ($searchString === '') {
|
||||
$pane->addDashlet(t('Ready to search'), 'search/hint');
|
||||
$pane->createEntry(t('Ready to search'), 'search/hint');
|
||||
return $this;
|
||||
}
|
||||
$searchUrls = array_merge($searchUrls, $moduleSearchUrls);
|
||||
@ -95,8 +95,8 @@ class SearchDashboard extends \Icinga\Web\Dashboard\Dashboard
|
||||
|
||||
foreach (array_reverse($searchUrls) as $searchUrl) {
|
||||
$title = $searchUrl->title . ': ' . $searchString;
|
||||
$pane->addDashlet($title, Url::fromPath($searchUrl->url, array('q' => $searchString)));
|
||||
$pane->getDashlet($title)->setProgressLabel(t('Searching'));
|
||||
$pane->createEntry($title, Url::fromPath($searchUrl->url, array('q' => $searchString)));
|
||||
$pane->getEntry($title)->setProgressLabel(t('Searching'));
|
||||
}
|
||||
|
||||
return $this;
|
||||
@ -104,11 +104,11 @@ class SearchDashboard extends \Icinga\Web\Dashboard\Dashboard
|
||||
|
||||
protected function assemble()
|
||||
{
|
||||
if (! $this->searchHome->getPane(self::SEARCH_PANE)->hasDashlets()) {
|
||||
if ($this->searchHome->getEntry(self::SEARCH_PANE)->hasEntries()) {
|
||||
throw new HttpNotFoundException(t('Page not found'));
|
||||
}
|
||||
|
||||
$this->add($this->searchHome->getPane(self::SEARCH_PANE)->getDashlets());
|
||||
$this->add($this->searchHome->getEntry(self::SEARCH_PANE)->getEntries());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,14 +35,10 @@ class DashboardSettings implements Tabextension
|
||||
public function apply(Tabs $tabs)
|
||||
{
|
||||
$url = Url::fromPath(Dashboard::BASE_ROUTE . '/settings');
|
||||
$url = empty($this->urlParam) ? $url : $url->addParams($this->urlParam);
|
||||
$tabs->add(
|
||||
'dashboard_settings',
|
||||
[
|
||||
'icon' => 'service',
|
||||
'url' => (string) $url,
|
||||
'priority' => -100
|
||||
]
|
||||
);
|
||||
$url = empty($this->urlParam) ? $url : $url->addParams($this->urlParam);
|
||||
$tabs->add('dashboard_settings', [
|
||||
'icon' => 'service',
|
||||
'url' => (string) $url,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@
|
||||
list-style-type: none;
|
||||
|
||||
label {
|
||||
width: 49%;
|
||||
width: 49.5%;
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
@ -93,24 +93,29 @@
|
||||
.dashlet-list-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: .4em;
|
||||
border: 1px solid @gray-light;
|
||||
background: @gray-lightest;
|
||||
border: 1px solid @gray-light;
|
||||
.rounded-corners();
|
||||
|
||||
section.caption, h1 {
|
||||
margin-left: .5em;
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-bottom: none;
|
||||
overflow: hidden;
|
||||
-webkit-line-clamp: 1;
|
||||
}
|
||||
|
||||
.caption {
|
||||
height: 3em;
|
||||
overflow-y: auto;
|
||||
font-size: 1.1em;
|
||||
color: @text-color-light;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
}
|
||||
|
||||
@ -141,16 +146,10 @@
|
||||
|
||||
// Add new home button of the dashboard manager
|
||||
.controls .add-home {
|
||||
.button();
|
||||
float: right;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
font-size: 1.2em;
|
||||
font-weight: 500;
|
||||
padding: .5em 1em;
|
||||
line-height: normal;
|
||||
text-decoration: none;
|
||||
border: 2px solid @icinga-blue;
|
||||
border-radius: .4em;
|
||||
color: @text-color-on-icinga-blue;
|
||||
background-color: @icinga-blue;
|
||||
}
|
||||
@ -160,27 +159,27 @@
|
||||
}
|
||||
|
||||
.action-link.add-dashboard {
|
||||
width: 81.5%;
|
||||
margin-top: .5em;
|
||||
width: 85%;
|
||||
margin: .5em 0 0;
|
||||
}
|
||||
|
||||
.action-link.add-dashlet, .action-link.add-dashboard {
|
||||
.rounded-corners();
|
||||
order: 1;
|
||||
font-size: 1.2em;
|
||||
font-weight: 500;
|
||||
padding: .6em 1em;
|
||||
border-radius: .3em;
|
||||
text-decoration: none;
|
||||
background-color: @low-sat-blue;
|
||||
}
|
||||
|
||||
.dashboard-list-control .dashlet-item-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-left: 2.2em;
|
||||
display: flex;
|
||||
width: 97.8%; // 100% - 2.2em margin-left
|
||||
|
||||
.dashlet-list-item {
|
||||
width: 49.4%;
|
||||
width: 49.7%;
|
||||
margin-bottom: .5em;
|
||||
background: transparent;
|
||||
}
|
||||
@ -191,14 +190,14 @@
|
||||
}
|
||||
|
||||
.dashboard-list-control {
|
||||
width: 80%;
|
||||
width: 85%;
|
||||
|
||||
h1.collapsible-header {
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
.action-link.add-dashlet {
|
||||
width: 99.5%;
|
||||
width: 97.8%;
|
||||
margin-left: 1.8em;
|
||||
}
|
||||
}
|
||||
@ -213,12 +212,16 @@
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
h1.collapsible-header a, h1.dashlet-header a {
|
||||
h1.collapsible-header a:not(.dashlet-title), h1.dashlet-header a:not(.dashlet-title) {
|
||||
margin-left: .3em;
|
||||
font-weight: normal;
|
||||
color: @icinga-blue;
|
||||
}
|
||||
|
||||
h1.dashlet-header a.dashlet-title {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.dashlets-list-info, .dashboard-list-info {
|
||||
.expand-icon {
|
||||
margin-top: .9em;
|
||||
@ -230,17 +233,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Dashboard home list controls only
|
||||
.home-list-control {
|
||||
width: 100%;
|
||||
|
||||
h1.collapsible-header.home {
|
||||
& > h1.collapsible-header {
|
||||
margin-left: 1.5em;
|
||||
margin-bottom: 0;
|
||||
margin-bottom: -1em;
|
||||
|
||||
& > a.disabled {
|
||||
pointer-events: none;
|
||||
cursor: default;
|
||||
}
|
||||
}
|
||||
|
||||
.action-link.add-dashboard {
|
||||
width: 81.6%;
|
||||
margin-left: 1.3em;
|
||||
.dashboard-list-control, .action-link.add-dashboard {
|
||||
margin-left: 1.4em;
|
||||
}
|
||||
|
||||
.dashboard-list-control {
|
||||
@ -249,20 +257,13 @@
|
||||
}
|
||||
|
||||
.dashlet-item-list {
|
||||
margin-left: 4em;
|
||||
}
|
||||
|
||||
.dashlets-list-info {
|
||||
margin-left: 2.2em;
|
||||
}
|
||||
|
||||
h1.collapsible-header {
|
||||
margin-left: 3em;
|
||||
margin-left: 2em;
|
||||
width: 98%; // 100% - 2em margin-left
|
||||
}
|
||||
|
||||
.action-link.add-dashlet {
|
||||
margin-left: 3.4em;
|
||||
width: 99.2%;
|
||||
margin-left: 1.6em;
|
||||
width: calc((49.74% * 2) - 1.2em); // 2x flex columns - own size
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -292,17 +293,37 @@
|
||||
}
|
||||
|
||||
// Make the submit buttons a bit bigger than the normal size
|
||||
.modal-form.icinga-controls .control-group.form-controls input[type="submit"] {
|
||||
.modal-form.icinga-controls .control-group.form-controls input[type="submit"],
|
||||
.control-group.form-controls .modal-cancel {
|
||||
min-width: 7em;
|
||||
font-size: 1.2em;
|
||||
margin-right: .4em;
|
||||
padding: ~"calc(@{vertical-padding} - 2px)" @horizontal-padding;
|
||||
}
|
||||
|
||||
// Remove and modal cancel buttons
|
||||
form.icinga-form .control-group.form-controls .remove-button {
|
||||
.cancel-button();
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.modal-form .form-controls .modal-cancel {
|
||||
padding: .5em 1em;
|
||||
}
|
||||
|
||||
.control-group.form-controls .modal-cancel {
|
||||
background-color: @low-sat-blue;
|
||||
border: none;
|
||||
}
|
||||
|
||||
// Drag and drop
|
||||
.drag-over {
|
||||
.sortable-chosen {
|
||||
.box-shadow();
|
||||
background: fade(@icinga-blue, 20);
|
||||
border: 5px @body-bg-color dashed;
|
||||
box-shadow: 4px 4px 4px 4px @black;
|
||||
}
|
||||
|
||||
.home-list-control.sortable-drag {
|
||||
width: calc(85% + 1.4em);
|
||||
}
|
||||
|
||||
.drag-active * {
|
||||
|
@ -4,19 +4,26 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
try {
|
||||
var Sortable = require('icinga/icinga-php-library/vendor/Sortable')
|
||||
} catch (e) {
|
||||
console.warn('Unable to provide Sortable. Library not available:', e);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Possible type of widgets this behavior is being applied to
|
||||
*
|
||||
* @type {object}
|
||||
*/
|
||||
const WIDGET_TYPES = { Dashlets : 'Dashlets', Dashboards : 'Dashboards', DashboardHomes : 'Homes' };
|
||||
const WIDGET_TYPES = { Dashlet : 'Dashlets', Dashboard : 'Dashboards', DashboardHome : 'Homes' };
|
||||
|
||||
Icinga.Behaviors = Icinga.Behaviors || {};
|
||||
|
||||
/**
|
||||
* Behavior for the enhanced Icinga Web 2 dashboards
|
||||
*
|
||||
* @param icinga {Icinga} The current Icinga Object
|
||||
* @param {Icinga} icinga The current Icinga Object
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
@ -25,283 +32,182 @@
|
||||
|
||||
this.icinga = icinga;
|
||||
|
||||
/**
|
||||
* Type of the widget which is currently being sorted
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.sortedWidgetType = WIDGET_TYPES.Dashlets;
|
||||
|
||||
/**
|
||||
* Widget container id which is currently being dragged
|
||||
*
|
||||
* @type {null|string}
|
||||
*/
|
||||
this.containerId = null;
|
||||
|
||||
// Register event handlers for drag and drop functionalities
|
||||
this.on('dragstart', '.widget-sortable', this.onDragStart, this);
|
||||
this.on('dragover', '.widget-sortable', this.onDragOver, this);
|
||||
this.on('dragleave', '.widget-sortable', this.onDragLeave, this);
|
||||
this.on('dragend', '.widget-sortable', this.onDragEnd, this);
|
||||
this.on('drop', '.widget-sortable', this.onDrop, this);
|
||||
this.on('rendered', '#main > .container', this.onRendered, this);
|
||||
this.on('end', '.dashboard-settings, .dashboard-list-control, .dashlet-list-item', this.elementDropped, this);
|
||||
// This is for the normal dashboard/dashlets view
|
||||
this.on('end', '.dashboard.content', this.elementDropped, this);
|
||||
};
|
||||
|
||||
Dashboard.prototype = new Icinga.EventListener();
|
||||
|
||||
/**
|
||||
* A user tries to drag an element, so make sure it's sortable and setup the procedure
|
||||
* Get the widget type of the given element
|
||||
*
|
||||
* @param event {Event} The `dragstart` event triggered when starting to drag the element
|
||||
* with a mouse click and begin to move it
|
||||
* @param {HTMLElement} target
|
||||
*
|
||||
* @returns {null|string}
|
||||
*/
|
||||
Dashboard.prototype.onDragStart = function (event) {
|
||||
let _this = event.data.self;
|
||||
let $target = $(event.target);
|
||||
|
||||
if (! _this.isDraggable($target)) {
|
||||
return false;
|
||||
Dashboard.prototype.getTypeFor = function (target) {
|
||||
if (target.matches('.dashboard-settings')) {
|
||||
return WIDGET_TYPES.DashboardHome;
|
||||
} else if (target.matches('.dashboard-item-list')) {
|
||||
return WIDGET_TYPES.Dashboard;
|
||||
} else if (target.matches('.dashlet-item-list') || target.matches('.dashboard.content')) {
|
||||
return WIDGET_TYPES.Dashlet;
|
||||
}
|
||||
|
||||
_this.containerId = $target.attr('id');
|
||||
$target.addClass('draggable-element');
|
||||
|
||||
let $parent = $target.parent()[0];
|
||||
// Prevents child elements from being the target of pointer events
|
||||
$($parent).children('.widget-sortable').addClass('drag-active');
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for drag over
|
||||
* Set up a request with the reordered widget and post the data to the controller
|
||||
*
|
||||
* Check that the target el is draggable and isn't the el itself
|
||||
* which is currently being dragged
|
||||
*
|
||||
* @param event {Event} The `drag over` event triggered when dragging over another dashlet
|
||||
*/
|
||||
Dashboard.prototype.onDragOver = function (event) {
|
||||
let $target = $(event.target);
|
||||
let _this = event.data.self;
|
||||
|
||||
// Moving an element arbitrarily elsewhere isn't allowed
|
||||
if (! _this.isDraggable($target) || ! _this.isDraggableSiblingOf($target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't show mouse drop cursor if the target element is the draggable element
|
||||
if ($target.attr('id') !== _this.containerId) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
$target.addClass('drag-over');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The element doesn't get dragged over anymore, so just remove the drag-over class
|
||||
*
|
||||
* @param event {Event} The `drag leave` event triggered when dragging over a dashlet
|
||||
* and leaving without dropping the draggable element
|
||||
*/
|
||||
Dashboard.prototype.onDragLeave = function (event) {
|
||||
let $target = $(event.target);
|
||||
let _this = event.data.self;
|
||||
|
||||
if (! _this.isDraggable($target) || ! _this.isDraggableSiblingOf($target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$target.removeClass('drag-over');
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove all class names added dynamically
|
||||
*
|
||||
* @param event {Event} The `drag end` event triggered when the draggable element is released
|
||||
*/
|
||||
Dashboard.prototype.onDragEnd = function (event) {
|
||||
let $target = $(event.target);
|
||||
let _this = event.data.self;
|
||||
|
||||
if (! _this.isDraggable($target) || ! _this.isDraggableSiblingOf($target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$target.removeClass('draggable-element');
|
||||
$target.removeClass('drag-over');
|
||||
|
||||
let $parent = $target.parent()[0];
|
||||
// The draggable is now released, so we have to remove the class to enable the pointer events again
|
||||
$($parent).children('.widget-sortable').removeClass('drag-active');
|
||||
};
|
||||
|
||||
/**
|
||||
* Event handler for on drop action
|
||||
*
|
||||
* @param event {Event} The `ondrop` event triggered when the dashlet has been dropped
|
||||
*/
|
||||
Dashboard.prototype.onDrop = function (event) {
|
||||
let $target = $(event.target);
|
||||
let _this = event.data.self;
|
||||
|
||||
// Don't allow to drop an element arbitrarily elsewhere
|
||||
if (! _this.isDraggable($target) || ! _this.isDraggableSiblingOf($target)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prevent default behaviors to allow the drop event
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const draggable = $target.parent().children('#' + _this.containerId);
|
||||
|
||||
// If the target element has been located before the draggable element,
|
||||
// insert the draggable before the target element otherwise after it
|
||||
if ($target.nextAll().filter(draggable).length) {
|
||||
draggable.insertBefore($target);
|
||||
} else {
|
||||
draggable.insertAfter($target);
|
||||
}
|
||||
|
||||
// Draggable element is now dropped, so drag-over class must also be removed
|
||||
$target.removeClass('drag-over');
|
||||
|
||||
if ($target.data('icinga-pane')) {
|
||||
_this.sortedWidgetType = WIDGET_TYPES.Dashboards;
|
||||
} else if ($target.data('icinga-home')) {
|
||||
_this.sortedWidgetType = WIDGET_TYPES.DashboardHomes;
|
||||
}
|
||||
|
||||
_this.sendReorderedWidgets($target);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get whether the given element is draggable
|
||||
*
|
||||
* @param $target {jQuery}
|
||||
* @param event
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Dashboard.prototype.isDraggable = function ($target) {
|
||||
return $target.attr('draggable');
|
||||
};
|
||||
|
||||
/**
|
||||
* Get whether the given element is sibling of the element currently being dragged
|
||||
*
|
||||
* @param $target {jQuery}
|
||||
*
|
||||
* @returns {number}
|
||||
*/
|
||||
Dashboard.prototype.isDraggableSiblingOf = function ($target) {
|
||||
return $target.parent().children('#' + this.containerId).length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set up a request with the reordered containers and post the data to the controller
|
||||
*
|
||||
* @param $target {jQuery}
|
||||
*/
|
||||
Dashboard.prototype.sendReorderedWidgets = function ($target) {
|
||||
let _this = this,
|
||||
Dashboard.prototype.elementDropped = function (event) {
|
||||
let _this = event.data.self,
|
||||
orgEvt = event.originalEvent,
|
||||
data = {};
|
||||
|
||||
switch (_this.sortedWidgetType) {
|
||||
case WIDGET_TYPES.DashboardHomes: {
|
||||
let $homes = [];
|
||||
$target.parent().children('.home-list-control.widget-sortable').each(function () {
|
||||
let home = $(this);
|
||||
if (typeof home.data('icinga-home') === 'undefined') {
|
||||
_this.icinga.logger.error(
|
||||
'[Dashboards] Dashboard home widget has no "icingaHome" data attribute registered: ',
|
||||
home[0]
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (orgEvt.to === orgEvt.from && orgEvt.newIndex === orgEvt.oldIndex) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$homes.push(home.data('icinga-home'));
|
||||
});
|
||||
|
||||
data = { ...$homes };
|
||||
let item = orgEvt.item;
|
||||
switch (_this.getTypeFor(orgEvt.to)) {
|
||||
case WIDGET_TYPES.DashboardHome: {
|
||||
let home = item.dataset.icingaHome;
|
||||
data[home] = orgEvt.newIndex;
|
||||
break;
|
||||
}
|
||||
case WIDGET_TYPES.Dashboards: {
|
||||
let $home, $panes = [];
|
||||
$target.parent().children('.dashboard-list-control.widget-sortable').each(function () {
|
||||
let pane = $(this);
|
||||
if (typeof pane.data('icinga-pane') === 'undefined') {
|
||||
_this.icinga.logger.error(
|
||||
'[Dashboards] Dashboard widget has no "icingaPane" data attribute registered: ',
|
||||
pane[0]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
pane = pane.data('icinga-pane').split('|', 2);
|
||||
if (! $home) {
|
||||
$home = pane.shift();
|
||||
}
|
||||
|
||||
$panes.push(pane.pop());
|
||||
});
|
||||
|
||||
data[$home] = $panes;
|
||||
break;
|
||||
}
|
||||
case WIDGET_TYPES.Dashlets: {
|
||||
let $home, $pane, $dashlets = [];
|
||||
$target.parent().children('.widget-sortable').each(function () {
|
||||
let dashlet = $(this);
|
||||
if (typeof dashlet.data('icinga-dashlet') === 'undefined') {
|
||||
_this.icinga.logger.error(
|
||||
'[Dashboards] Dashlet widget has no "icingaDashlet" data attribute registered: ',
|
||||
dashlet[0]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $home && ! $pane) {
|
||||
let pane = dashlet.parent();
|
||||
if (typeof pane.data('icinga-pane') === 'undefined') {
|
||||
// Nested parents
|
||||
pane = pane.parent();
|
||||
if (typeof pane.data('icinga-pane') === 'undefined') {
|
||||
_this.icinga.logger.error(
|
||||
'[Dashboards] Dashlet parent widget has no "icingaPane" data attribute registered: ',
|
||||
pane[0]
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
pane = pane.data('icinga-pane').split('|', 2);
|
||||
$home = pane.shift();
|
||||
$pane = pane.shift();
|
||||
}
|
||||
|
||||
$dashlets.push(dashlet.data('icinga-dashlet'));
|
||||
});
|
||||
|
||||
if ($home && $pane) {
|
||||
data[$home] = { [$pane] : $dashlets };
|
||||
case WIDGET_TYPES.Dashboard: {
|
||||
let pane = item.dataset.icingaPane,
|
||||
home = orgEvt.to.closest('.home-list-control').dataset.icingaHome;
|
||||
if (orgEvt.to !== orgEvt.from) {
|
||||
data.originals = {
|
||||
originalHome : orgEvt.from.closest('.home-list-control').dataset.icingaHome,
|
||||
originalPane : pane
|
||||
};
|
||||
}
|
||||
|
||||
data[home] = { [pane] : orgEvt.newIndex };
|
||||
break;
|
||||
}
|
||||
case WIDGET_TYPES.Dashlet: {
|
||||
let dashlet = item.dataset.icingaDashlet,
|
||||
pane,
|
||||
home;
|
||||
|
||||
if (orgEvt.to.matches('.dashboard.content')) {
|
||||
let parentData = orgEvt.to.dataset.icingaPane.split('|', 2);
|
||||
home = parentData.shift();
|
||||
pane = parentData.shift();
|
||||
|
||||
data.redirectPath = 'dashboards';
|
||||
} else { // Dashboard manager view
|
||||
let parent = orgEvt.to.closest('.dashboard-list-control');
|
||||
pane = parent.dataset.icingaPane;
|
||||
home = parent.closest('.home-list-control').dataset.icingaHome;
|
||||
|
||||
if (orgEvt.to !== orgEvt.from) {
|
||||
let parent = orgEvt.from.closest('.dashboard-list-control');
|
||||
data.originals = {
|
||||
originalHome : parent.closest('.home-list-control').dataset.icingaHome,
|
||||
originalPane : parent.dataset.icingaPane
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dashlet = { [dashlet] : orgEvt.newIndex };
|
||||
data[home] = { [pane] : dashlet };
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(data).length) {
|
||||
data.Type = _this.sortedWidgetType;
|
||||
data.Type = _this.getTypeFor(orgEvt.to);
|
||||
if (! data.hasOwnProperty('originals')) {
|
||||
data.originals = null;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
context : _this,
|
||||
type : 'post',
|
||||
url : _this.icinga.config.baseUrl + '/dashboards/reorder-widgets',
|
||||
headers : { 'Accept' : 'application/json' },
|
||||
contentType : 'application/json',
|
||||
data : JSON.stringify(data),
|
||||
});
|
||||
if (! data.hasOwnProperty('redirectPath')) {
|
||||
data.redirectPath = 'dashboards/settings';
|
||||
}
|
||||
|
||||
data = { dashboardData : JSON.stringify(data) };
|
||||
let url = _this.icinga.config.baseUrl + '/dashboards/reorder-widgets';
|
||||
_this.icinga.loader.loadUrl(url, $('#col1'), data, 'post');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get whether the given element is a valid target of the drag & drop events
|
||||
*
|
||||
* @param to
|
||||
* @param from
|
||||
* @param item
|
||||
* @param event
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Dashboard.prototype.isValid = function (to, from, item, event) {
|
||||
if (typeof from.options.group === 'undefined' || typeof to.options.group === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return from.options.group.name === to.options.group.name;
|
||||
};
|
||||
|
||||
Dashboard.prototype.onRendered = function (e) {
|
||||
let _this = e.data.self;
|
||||
$(e.target).find('.dashboard-settings, .dashboard.content, .dashboard-item-list, .dashlet-item-list').each(function () {
|
||||
let groupName = _this.getTypeFor(this),
|
||||
draggable,
|
||||
handle;
|
||||
|
||||
switch (groupName) {
|
||||
case WIDGET_TYPES.DashboardHome: {
|
||||
groupName = WIDGET_TYPES.DashboardHome;
|
||||
draggable = '.home-list-control';
|
||||
handle = '.home-list-control > h1';
|
||||
break;
|
||||
}
|
||||
case WIDGET_TYPES.Dashboard: {
|
||||
groupName = WIDGET_TYPES.Dashboard;
|
||||
draggable = '.dashboard-list-control';
|
||||
handle = '.dashboard-list-control > h1'
|
||||
break;
|
||||
}
|
||||
case WIDGET_TYPES.Dashlet: {
|
||||
groupName = WIDGET_TYPES.Dashlet;
|
||||
if (this.matches('.dashboard.content')) {
|
||||
draggable = '> .container';
|
||||
} else {
|
||||
draggable = '.dashlet-list-item';
|
||||
}
|
||||
|
||||
handle = draggable;
|
||||
}
|
||||
}
|
||||
|
||||
let options = {
|
||||
scroll : true,
|
||||
invertSwap : true,
|
||||
dataIdAttr : 'id',
|
||||
direction : 'vertical',
|
||||
draggable : draggable,
|
||||
handle : handle,
|
||||
group : {
|
||||
name : groupName,
|
||||
put : _this['isValid'],
|
||||
}
|
||||
};
|
||||
|
||||
Sortable.create(this, options);
|
||||
});
|
||||
};
|
||||
|
||||
Icinga.Behaviors.Dashboard = Dashboard;
|
||||
|
||||
})(Icinga, jQuery);
|
||||
|
Loading…
x
Reference in New Issue
Block a user