diff options
Diffstat (limited to 'application/controllers')
-rw-r--r-- | application/controllers/ConfigController.php | 30 | ||||
-rw-r--r-- | application/controllers/GraphController.php | 172 | ||||
-rw-r--r-- | application/controllers/HostsController.php | 112 | ||||
-rw-r--r-- | application/controllers/ListController.php | 192 | ||||
-rw-r--r-- | application/controllers/MonitoringGraphController.php | 155 | ||||
-rw-r--r-- | application/controllers/ServicesController.php | 115 |
6 files changed, 776 insertions, 0 deletions
diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php new file mode 100644 index 0000000..f627e36 --- /dev/null +++ b/application/controllers/ConfigController.php @@ -0,0 +1,30 @@ +<?php + +namespace Icinga\Module\Graphite\Controllers; + +use Icinga\Module\Graphite\Forms\Config\AdvancedForm; +use Icinga\Module\Graphite\Forms\Config\BackendForm; +use Icinga\Web\Controller; + +class ConfigController extends Controller +{ + public function init() + { + $this->assertPermission('config/modules'); + parent::init(); + } + + public function backendAction() + { + $this->view->form = $form = new BackendForm(); + $form->setIniConfig($this->Config())->handleRequest(); + $this->view->tabs = $this->Module()->getConfigTabs()->activate('backend'); + } + + public function advancedAction() + { + $this->view->form = $form = new AdvancedForm(); + $form->setIniConfig($this->Config())->handleRequest(); + $this->view->tabs = $this->Module()->getConfigTabs()->activate('advanced'); + } +} diff --git a/application/controllers/GraphController.php b/application/controllers/GraphController.php new file mode 100644 index 0000000..c8dc7db --- /dev/null +++ b/application/controllers/GraphController.php @@ -0,0 +1,172 @@ +<?php + +namespace Icinga\Module\Graphite\Controllers; + +use Icinga\Exception\Http\HttpBadRequestException; +use Icinga\Exception\Http\HttpNotFoundException; +use Icinga\Module\Graphite\Graphing\GraphingTrait; +use Icinga\Module\Graphite\Util\IcingadbUtils; +use Icinga\Module\Graphite\Web\Widget\Graphs; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use Icinga\Web\Controller; +use Icinga\Web\UrlParams; +use ipl\Orm\Model; +use ipl\Stdlib\Filter; + +class GraphController extends Controller +{ + use GraphingTrait; + + /** + * The URL parameters for the graph + * + * @var string[] + */ + protected $graphParamsNames = [ + 'start', 'end', + 'width', 'height', + 'legend', + 'template', 'default_template', + 'bgcolor', 'fgcolor', + 'majorGridLineColor', 'minorGridLineColor' + ]; + + /** + * The URL parameters for metrics filtering + * + * @var UrlParams + */ + protected $filterParams; + + /** + * The URL parameters for the graph + * + * @var string[] + */ + protected $graphParams = []; + + public function init() + { + parent::init(); + + $this->filterParams = clone $this->getRequest()->getUrl()->getParams(); + + foreach ($this->graphParamsNames as $paramName) { + $this->graphParams[$paramName] = $this->filterParams->shift($paramName); + } + } + + public function serviceAction() + { + $hostName = $this->filterParams->getRequired('host.name'); + $serviceName = $this->filterParams->getRequired('service.name'); + $icingadbUtils = IcingadbUtils::getInstance(); + $query = Service::on($icingadbUtils->getDb()) + ->with('state') + ->with('host'); + + $query->filter(Filter::all( + Filter::equal('service.name', $serviceName), + Filter::equal('service.host.name', $hostName) + )); + + $icingadbUtils->applyRestrictions($query); + + /** @var Service $service */ + $service = $query->first(); + + if ($service === null) { + throw new HttpNotFoundException($this->translate('No such service')); + } + + $checkCommandColumn = $service->vars[Graphs::getObscuredCheckCommandCustomVar()] ?? null; + + $this->supplyImage( + $service, + $service->checkcommand_name, + $checkCommandColumn + ); + } + + public function hostAction() + { + $hostName = $this->filterParams->getRequired('host.name'); + $icingadbUtils = IcingadbUtils::getInstance(); + $query = Host::on($icingadbUtils->getDb())->with('state'); + $query->filter(Filter::equal('host.name', $hostName)); + + $icingadbUtils->applyRestrictions($query); + + /** @var Host $host */ + $host = $query->first(); + + if ($host === null) { + throw new HttpNotFoundException($this->translate('No such host')); + } + + $checkCommandColumn = $host->vars[Graphs::getObscuredCheckCommandCustomVar()] ?? null; + + $this->supplyImage( + $host, + $host->checkcommand_name, + $checkCommandColumn + ); + } + + /** + * Do all monitored object type independent actions + * + * @param Model $object The object to render the graphs for + * @param string $checkCommand The check command of the object we supply an image for + * @param string|null $obscuredCheckCommand The "real" check command (if any) of the object we + * display graphs for + */ + protected function supplyImage($object, $checkCommand, $obscuredCheckCommand) + { + if (isset($this->graphParams['default_template'])) { + $urlParam = 'default_template'; + $templates = $this->getAllTemplates()->getDefaultTemplates(); + } else { + $urlParam = 'template'; + $templates = $this->getAllTemplates()->getTemplates( + $obscuredCheckCommand === null ? $checkCommand : $obscuredCheckCommand + ); + } + + if (! isset($templates[$this->graphParams[$urlParam]])) { + throw new HttpNotFoundException($this->translate('No such template')); + } + + $charts = $templates[$this->graphParams[$urlParam]]->getCharts( + static::getMetricsDataSource(), + $object, + array_map('rawurldecode', $this->filterParams->toArray(false)) + ); + + switch (count($charts)) { + case 0: + throw new HttpNotFoundException($this->translate('No such graph')); + + case 1: + $charts[0] + ->setFrom($this->graphParams['start']) + ->setUntil($this->graphParams['end']) + ->setWidth($this->graphParams['width']) + ->setHeight($this->graphParams['height']) + ->setBackgroundColor($this->graphParams['bgcolor']) + ->setForegroundColor($this->graphParams['fgcolor']) + ->setMajorGridLineColor($this->graphParams['majorGridLineColor']) + ->setMinorGridLineColor($this->graphParams['minorGridLineColor']) + ->setShowLegend((bool) $this->graphParams['legend']) + ->serveImage($this->getResponse()); + + // not falling through, serveImage exits + default: + throw new HttpBadRequestException('%s', $this->translate( + 'Graphite Web yields more than one metric for the given filter.' + . ' Please specify a more precise filter.' + )); + } + } +} diff --git a/application/controllers/HostsController.php b/application/controllers/HostsController.php new file mode 100644 index 0000000..f77281a --- /dev/null +++ b/application/controllers/HostsController.php @@ -0,0 +1,112 @@ +<?php + +/* Icinga Graphite Web | (c) 2022 Icinga GmbH | GPLv2 */ + +namespace Icinga\Module\Graphite\Controllers; + +use GuzzleHttp\Psr7\ServerRequest; +use Icinga\Module\Graphite\Web\Controller\IcingadbGraphiteController; +use Icinga\Module\Graphite\Web\Controller\TimeRangePickerTrait; +use Icinga\Module\Graphite\Web\Widget\IcingadbGraphs; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions; +use Icinga\Web\Url; +use ipl\Html\HtmlString; +use ipl\Stdlib\Filter; +use ipl\Web\Control\LimitControl; +use ipl\Web\Control\SortControl; + +class HostsController extends IcingadbGraphiteController +{ + use TimeRangePickerTrait; + + public function indexAction() + { + if (! $this->useIcingadbAsBackend) { + $params = urldecode($this->params->get('legacyParams')); + $this->redirectNow(Url::fromPath('graphite/list/hosts')->setQueryString($params)); + } + + // shift graph params to avoid exception + $graphRange = $this->params->shift('graph_range'); + $baseFilter = $graphRange ? Filter::equal('graph_range', $graphRange) : null; + foreach ($this->graphParams as $param) { + $this->params->shift($param); + } + + $this->addTitleTab(t('Hosts')); + + $db = $this->getDb(); + + $hosts = Host::on($db)->with('state'); + $hosts->filter(Filter::like('state.performance_data', '*')); + + $this->applyRestrictions($hosts); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($hosts); + $sortControl = $this->createSortControl($hosts, ['host.display_name' => t('Hostname')]); + + $searchBar = $this->createSearchBar( + $hosts, + array_merge( + [$limitControl->getLimitParam(), $sortControl->getSortParam()], + $this->graphParams + ) + ); + + if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) { + if ($searchBar->hasBeenSubmitted()) { + $filter = $this->getFilter(); + } else { + $this->addControl($searchBar); + $this->sendMultipartUpdate(); + return; + } + } else { + $filter = $searchBar->getFilter(); + } + + $hosts->filter($filter); + + $this->addControl($paginationControl); + $this->addControl($sortControl); + $this->addControl($limitControl); + $this->addControl($searchBar); + $this->handleTimeRangePickerRequest(); + $this->addControl(HtmlString::create($this->renderTimeRangePicker($this->view))); + + $this->addContent( + (new IcingadbGraphs($hosts->execute())) + ->setBaseFilter($baseFilter) + ); + + if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) { + $this->sendMultipartUpdate(); + } + + $this->setAutorefreshInterval(30); + } + + public function completeAction() + { + $suggestions = new ObjectSuggestions(); + $suggestions->setModel(Host::class); + $suggestions->forRequest(ServerRequest::fromGlobals()); + $this->getDocument()->add($suggestions); + } + + public function searchEditorAction() + { + $editor = $this->createSearchEditor( + Host::on($this->getDb()), + array_merge( + [LimitControl::DEFAULT_LIMIT_PARAM, SortControl::DEFAULT_SORT_PARAM], + $this->graphParams + ) + ); + + $this->getDocument()->add($editor); + $this->setTitle(t('Adjust Filter')); + } +} diff --git a/application/controllers/ListController.php b/application/controllers/ListController.php new file mode 100644 index 0000000..46d8321 --- /dev/null +++ b/application/controllers/ListController.php @@ -0,0 +1,192 @@ +<?php + +namespace Icinga\Module\Graphite\Controllers; + +use Icinga\Data\Filter\Filter; +use Icinga\Module\Graphite\Util\TimeRangePickerTools; +use Icinga\Module\Graphite\Web\Controller\MonitoringAwareController; +use Icinga\Module\Graphite\Web\Controller\TimeRangePickerTrait; +use Icinga\Module\Icingadb\Compat\UrlMigrator; +use Icinga\Module\Monitoring\DataView\DataView; +use Icinga\Module\Monitoring\Object\Host; +use Icinga\Module\Monitoring\Object\Service; +use Icinga\Web\Url; +use Icinga\Web\Widget\Tabextension\DashboardAction; +use Icinga\Web\Widget\Tabextension\MenuAction; +use Icinga\Web\Widget\Tabextension\OutputFormat; +use ipl\Web\Filter\QueryString; + +class ListController extends MonitoringAwareController +{ + use TimeRangePickerTrait; + + public function init() + { + parent::init(); + $this->getTabs() + ->extend(new OutputFormat([OutputFormat::TYPE_CSV, OutputFormat::TYPE_JSON])) + ->extend(new DashboardAction()) + ->extend(new MenuAction()); + } + + public function hostsAction() + { + if ($this->useIcingadbAsBackend) { + $legacyParams = urlencode($this->params->toString()); + $params = QueryString::render( + UrlMigrator::transformFilter( + QueryString::parse($this->params->toString()) + ) + ); + + $url = Url::fromPath('graphite/hosts') + ->setQueryString($params); + + if ($legacyParams) { + $url->setParam('legacyParams', $legacyParams); + } + + $this->redirectNow($url); + } + + $this->addTitleTab( + 'hosts', + mt('monitoring', 'Hosts'), + mt('monitoring', 'List hosts') + ); + + $hostsQuery = $this->applyMonitoringRestriction( + $this->backend->select()->from('hoststatus', ['host_name']) + ); + + $hostsQuery->applyFilter(Filter::expression('host_perfdata', '!=', '')); + + $this->view->baseUrl = $baseUrl = Url::fromPath('monitoring/host/show'); + TimeRangePickerTools::copyAllRangeParameters( + $baseUrl->getParams(), + $this->getRequest()->getUrl()->getParams() + ); + + $this->filterQuery($hostsQuery); + $this->setupPaginationControl($hostsQuery); + $this->setupLimitControl(); + $this->setupSortControl(['host_display_name' => mt('monitoring', 'Hostname')], $hostsQuery); + + $hosts = []; + foreach ($hostsQuery->peekAhead($this->view->compact) as $host) { + $host = new Host($this->backend, $host->host_name); + $host->fetch(); + $hosts[] = $host; + } + + $this->handleTimeRangePickerRequest(); + $this->view->timeRangePicker = $this->renderTimeRangePicker($this->view); + $this->view->hosts = $hosts; + $this->view->hasMoreHosts = ! $this->view->compact && $hostsQuery->hasMore(); + + $this->setAutorefreshInterval(30); + } + + public function servicesAction() + { + if ($this->useIcingadbAsBackend) { + $legacyParams = urlencode($this->params->toString()); + $params = QueryString::render( + UrlMigrator::transformFilter( + QueryString::parse($this->params->toString()) + ) + ); + + $url = Url::fromPath('graphite/services') + ->setQueryString($params); + + if ($legacyParams) { + $url->setParam('legacyParams', $legacyParams); + } + + $this->redirectNow($url); + } + + $this->addTitleTab( + 'services', + mt('monitoring', 'Services'), + mt('monitoring', 'List services') + ); + + $servicesQuery = $this->applyMonitoringRestriction( + $this->backend->select()->from('servicestatus', ['host_name', 'service_description']) + ); + + $servicesQuery->applyFilter(Filter::expression('service_perfdata', '!=', '')); + + $this->view->hostBaseUrl = $hostBaseUrl = Url::fromPath('monitoring/host/show'); + TimeRangePickerTools::copyAllRangeParameters( + $hostBaseUrl->getParams(), + $this->getRequest()->getUrl()->getParams() + ); + + $this->view->serviceBaseUrl = $serviceBaseUrl = Url::fromPath('monitoring/service/show'); + TimeRangePickerTools::copyAllRangeParameters( + $serviceBaseUrl->getParams(), + $this->getRequest()->getUrl()->getParams() + ); + + $this->filterQuery($servicesQuery); + $this->setupPaginationControl($servicesQuery); + $this->setupLimitControl(); + $this->setupSortControl([ + 'service_display_name' => mt('monitoring', 'Service Name'), + 'host_display_name' => mt('monitoring', 'Hostname') + ], $servicesQuery); + + $services = []; + foreach ($servicesQuery->peekAhead($this->view->compact) as $service) { + $service = new Service($this->backend, $service->host_name, $service->service_description); + $service->fetch(); + $services[] = $service; + } + + $this->handleTimeRangePickerRequest(); + $this->view->timeRangePicker = $this->renderTimeRangePicker($this->view); + $this->view->services = $services; + $this->view->hasMoreServices = ! $this->view->compact && $servicesQuery->hasMore(); + + $this->setAutorefreshInterval(30); + } + + /** + * Apply filters on a DataView + * + * @param DataView $dataView The DataView to apply filters on + */ + protected function filterQuery(DataView $dataView) + { + $this->setupFilterControl( + $dataView, + null, + null, + array_merge( + ['format', 'stateType', 'addColumns', 'problems', 'graphs_limit'], + TimeRangePickerTools::getAllRangeParameters() + ) + ); + $this->handleFormatRequest($dataView); + } + + /** + * Add title tab + * + * @param string $action + * @param string $title + * @param string $tip + */ + protected function addTitleTab($action, $title, $tip) + { + $this->getTabs()->add($action, [ + 'title' => $tip, + 'label' => $title, + 'url' => Url::fromRequest(), + 'active' => true + ]); + } +} diff --git a/application/controllers/MonitoringGraphController.php b/application/controllers/MonitoringGraphController.php new file mode 100644 index 0000000..583c859 --- /dev/null +++ b/application/controllers/MonitoringGraphController.php @@ -0,0 +1,155 @@ +<?php + +namespace Icinga\Module\Graphite\Controllers; + +use Icinga\Exception\Http\HttpBadRequestException; +use Icinga\Exception\Http\HttpNotFoundException; +use Icinga\Module\Graphite\Graphing\GraphingTrait; +use Icinga\Module\Graphite\Web\Controller\MonitoringAwareController; +use Icinga\Module\Graphite\Web\Widget\Graphs; +use Icinga\Module\Monitoring\Object\Host; +use Icinga\Module\Monitoring\Object\MonitoredObject; +use Icinga\Module\Monitoring\Object\Service; +use Icinga\Web\UrlParams; + +class MonitoringGraphController extends MonitoringAwareController +{ + use GraphingTrait; + + /** + * The URL parameters for the graph + * + * @var string[] + */ + protected $graphParamsNames = [ + 'start', 'end', + 'width', 'height', + 'legend', + 'template', 'default_template', + 'bgcolor', 'fgcolor', + 'majorGridLineColor', 'minorGridLineColor' + ]; + + /** + * The URL parameters for metrics filtering + * + * @var UrlParams + */ + protected $filterParams; + + /** + * The URL parameters for the graph + * + * @var string[] + */ + protected $graphParams = []; + + public function init() + { + parent::init(); + + $this->filterParams = clone $this->getRequest()->getUrl()->getParams(); + + foreach ($this->graphParamsNames as $paramName) { + $this->graphParams[$paramName] = $this->filterParams->shift($paramName); + } + } + + public function hostAction() + { + $hostName = $this->filterParams->getRequired('host.name'); + $checkCommandColumn = '_host_' . Graphs::getObscuredCheckCommandCustomVar(); + $host = $this->applyMonitoringRestriction( + $this->backend->select()->from('hoststatus', ['host_check_command', $checkCommandColumn]) + ) + ->where('host_name', $hostName) + ->limit(1) // just to be sure to save a few CPU cycles + ->fetchRow(); + + if ($host === false) { + throw new HttpNotFoundException('%s', $this->translate('No such host')); + } + + $this->supplyImage(new Host($this->backend, $hostName), $host->host_check_command, $host->$checkCommandColumn); + } + + public function serviceAction() + { + $hostName = $this->filterParams->getRequired('host.name'); + $serviceName = $this->filterParams->getRequired('service.name'); + $checkCommandColumn = '_service_' . Graphs::getObscuredCheckCommandCustomVar(); + $service = $this->applyMonitoringRestriction( + $this->backend->select()->from('servicestatus', ['service_check_command', $checkCommandColumn]) + ) + ->where('host_name', $hostName) + ->where('service_description', $serviceName) + ->limit(1) // just to be sure to save a few CPU cycles + ->fetchRow(); + + if ($service === false) { + throw new HttpNotFoundException('%s', $this->translate('No such service')); + } + + $this->supplyImage( + new Service($this->backend, $hostName, $serviceName), + $service->service_check_command, + $service->$checkCommandColumn + ); + } + + /** + * Do all monitored object type independend actions + * + * @param MonitoredObject $object The object to render the graphs for + * @param string $checkCommand The check command of the object we supply an image for + * @param string|null $obscuredCheckCommand The "real" check command (if any) of the object we + * display graphs for + */ + protected function supplyImage($object, $checkCommand, $obscuredCheckCommand) + { + if (isset($this->graphParams['default_template'])) { + $urlParam = 'default_template'; + $templates = $this->getAllTemplates()->getDefaultTemplates(); + } else { + $urlParam = 'template'; + $templates = $this->getAllTemplates()->getTemplates( + $obscuredCheckCommand === null ? $checkCommand : $obscuredCheckCommand + ); + } + + if (! isset($templates[$this->graphParams[$urlParam]])) { + throw new HttpNotFoundException($this->translate('No such template')); + } + + $charts = $templates[$this->graphParams[$urlParam]]->getCharts( + static::getMetricsDataSource(), + $object, + array_map('rawurldecode', $this->filterParams->toArray(false)) + ); + + switch (count($charts)) { + case 0: + throw new HttpNotFoundException($this->translate('No such graph')); + + case 1: + $charts[0] + ->setFrom($this->graphParams['start']) + ->setUntil($this->graphParams['end']) + ->setWidth($this->graphParams['width']) + ->setHeight($this->graphParams['height']) + ->setBackgroundColor($this->graphParams['bgcolor']) + ->setForegroundColor($this->graphParams['fgcolor']) + ->setMajorGridLineColor($this->graphParams['majorGridLineColor']) + ->setMinorGridLineColor($this->graphParams['minorGridLineColor']) + ->setShowLegend((bool) $this->graphParams['legend']) + ->serveImage($this->getResponse()); + + // not falling through, serveImage exits + default: + throw new HttpBadRequestException('%s', $this->translate( + 'Graphite Web yields more than one metric for the given filter.' + . ' Please specify a more precise filter.' + )); + } + } +} diff --git a/application/controllers/ServicesController.php b/application/controllers/ServicesController.php new file mode 100644 index 0000000..212ad1f --- /dev/null +++ b/application/controllers/ServicesController.php @@ -0,0 +1,115 @@ +<?php + +namespace Icinga\Module\Graphite\Controllers; + +use GuzzleHttp\Psr7\ServerRequest; +use Icinga\Module\Graphite\Web\Controller\IcingadbGraphiteController; +use Icinga\Module\Graphite\Web\Controller\TimeRangePickerTrait; +use Icinga\Module\Graphite\Web\Widget\IcingadbGraphs; +use Icinga\Module\Icingadb\Model\Service; +use Icinga\Module\Icingadb\Web\Control\SearchBar\ObjectSuggestions; +use Icinga\Web\Url; +use ipl\Html\HtmlString; +use ipl\Stdlib\Filter; +use ipl\Web\Control\LimitControl; +use ipl\Web\Control\SortControl; + +class ServicesController extends IcingadbGraphiteController +{ + use TimeRangePickerTrait; + + public function indexAction() + { + if (! $this->useIcingadbAsBackend) { + $params = urldecode($this->params->get('legacyParams')); + $this->redirectNow(Url::fromPath('graphite/list/services')->setQueryString($params)); + } + + // shift graph params to avoid exception + $graphRange = $this->params->shift('graph_range'); + $baseFilter = $graphRange ? Filter::equal('graph_range', $graphRange) : null; + foreach ($this->graphParams as $param) { + $this->params->shift($param); + } + + $this->addTitleTab(t('Services')); + + $db = $this->getDb(); + + $services = Service::on($db) + ->with('state') + ->with('host'); + $services->filter(Filter::like('state.performance_data', '*')); + + $this->applyRestrictions($services); + + $limitControl = $this->createLimitControl(); + $paginationControl = $this->createPaginationControl($services); + $sortControl = $this->createSortControl($services, [ + 'service.display_name' => t('Servicename'), + 'host.display_name' => t('Hostname') + ]); + + $searchBar = $this->createSearchBar( + $services, + array_merge( + [$limitControl->getLimitParam(), $sortControl->getSortParam()], + $this->graphParams + ) + ); + + if ($searchBar->hasBeenSent() && ! $searchBar->isValid()) { + if ($searchBar->hasBeenSubmitted()) { + $filter = $this->getFilter(); + } else { + $this->addControl($searchBar); + $this->sendMultipartUpdate(); + return; + } + } else { + $filter = $searchBar->getFilter(); + } + + $services->filter($filter); + + $this->addControl($paginationControl); + $this->addControl($sortControl); + $this->addControl($limitControl); + $this->addControl($searchBar); + $this->handleTimeRangePickerRequest(); + $this->addControl(HtmlString::create($this->renderTimeRangePicker($this->view))); + + $this->addContent( + (new IcingadbGraphs($services->execute())) + ->setBaseFilter($baseFilter) + ); + + if (! $searchBar->hasBeenSubmitted() && $searchBar->hasBeenSent()) { + $this->sendMultipartUpdate(); + } + + $this->setAutorefreshInterval(30); + } + + public function completeAction() + { + $suggestions = new ObjectSuggestions(); + $suggestions->setModel(Service::class); + $suggestions->forRequest(ServerRequest::fromGlobals()); + $this->getDocument()->add($suggestions); + } + + public function searchEditorAction() + { + $editor = $this->createSearchEditor( + Service::on($this->getDb()), + array_merge( + [LimitControl::DEFAULT_LIMIT_PARAM, SortControl::DEFAULT_SORT_PARAM], + $this->graphParams + ) + ); + + $this->getDocument()->add($editor); + $this->setTitle(t('Adjust Filter')); + } +} |