-
Notifications
You must be signed in to change notification settings - Fork 13
Implement Webdriver #88
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
c803fcd
b04bf63
529a1c7
ec4097f
a890086
1607807
42fb217
380b66a
7a28a6a
a634193
1e255ef
835e92b
059642c
1168851
c66980d
48d7829
4161126
b863a7a
fb9f483
df37ddb
3457afc
3becc7f
ea4ce28
751d564
f2fc458
408175c
fbdc9dc
299000b
0680aa4
5e61ca1
cafe3a7
bf2c076
f4d2fc3
eb13c9b
059f197
93766d0
7df8e4b
0d7a86b
1b1e3e7
ef93d16
e48d408
77ae387
40e04e1
55a5a44
aa7704c
c5ab073
92a0d2b
085922b
eef4330
5854c67
1dc3217
322bbeb
b08e5e2
174faf2
958467f
0a5dfa2
907a1fd
6861696
50f297c
0cec004
f03bfc6
c14c7a5
5864d1f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,10 +6,20 @@ | |
| namespace Icinga\Module\Pdfexport\Controllers; | ||
|
|
||
| use Icinga\Application\Config; | ||
| use Icinga\Module\Pdfexport\Forms\ChromeBinaryForm; | ||
| use Icinga\Web\Controller; | ||
| use Icinga\Module\Pdfexport\Forms\BackendConfigForm; | ||
| use Icinga\Web\Form\ConfigSectionForm; | ||
| use Icinga\Web\Notification; | ||
| use ipl\Html\Attributes; | ||
| use ipl\Html\Form; | ||
| use ipl\Html\HtmlString; | ||
| use ipl\Html\Table; | ||
| use ipl\Web\Compat\CompatController; | ||
| use Icinga\Web\Widget\Tabs; | ||
| use ipl\Web\Widget\ButtonLink; | ||
| use ipl\Web\Widget\Icon; | ||
| use ipl\Web\Widget\Link; | ||
|
|
||
| class ConfigController extends Controller | ||
| class ConfigController extends CompatController | ||
| { | ||
| public function init() | ||
| { | ||
|
|
@@ -18,14 +28,100 @@ public function init() | |
| parent::init(); | ||
| } | ||
|
|
||
| public function chromeAction() | ||
| public function backendsAction(): void | ||
| { | ||
| $form = (new ChromeBinaryForm()) | ||
| ->setIniConfig(Config::module('pdfexport')); | ||
| $button = new ButtonLink( | ||
| $this->translate('Create a New Backend'), | ||
| 'pdfexport/config/createbackend', | ||
| 'plus', | ||
| ['title' => $this->translate('Create a New Backend')], | ||
| ); | ||
| $button->setBaseTarget('_next'); | ||
| $this->addContent($button); | ||
|
|
||
| $form->handleRequest(); | ||
| $table = new Table(); | ||
| $table->setAttributes(Attributes::create([ | ||
| 'class' => 'table-row-selectable common-table', | ||
| 'data-base-target' => '_next', | ||
| ])); | ||
| $table->add(Table::tr([ | ||
| Table::th($this->translate('Backend')), | ||
| Table::th($this->translate('Priority')), | ||
| ])); | ||
|
|
||
| $this->view->tabs = $this->Module()->getConfigTabs()->activate('chrome'); | ||
| $this->view->form = $form; | ||
| $config = Config::module('pdfexport'); | ||
|
|
||
| $sections = []; | ||
| foreach ($config as $name => $data) { | ||
| $sections[] = [$name, $data, (int) $data->get('priority')]; | ||
| } | ||
|
|
||
| usort($sections, function ($a, $b) { | ||
| return $a[2] <=> $b[2]; | ||
| }); | ||
|
|
||
| foreach ($sections as [$name, $data]) { | ||
| $table->add(Table::tr([ | ||
| Table::td([ | ||
| new Icon('print'), | ||
| new Link($name, 'pdfexport/config/backend?backend=' . $name), | ||
| ]), | ||
| Table::td($data->get('priority')), | ||
| ], [ | ||
| 'class' => 'clickable', | ||
| ])); | ||
| } | ||
|
|
||
| $this->mergeTabs($this->Module()->getConfigTabs()->activate('backends')); | ||
| $this->addContent($table); | ||
| } | ||
|
|
||
| public function backendAction(): void | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Being able to rename a backend would be nice. See https://github.com/Icinga/icinga-sso-web/pull/3
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would leave that up to Icinga/icingaweb2#5480
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't be necessary if you use random IDs as section keys like https://github.com/Icinga/icinga-sso-web/pull/3.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Being able to deactivate a backend temporarily for testing would be nice, but I guess changing priorities will do it as well. You decide. |
||
| { | ||
| $name = $this->params->shiftRequired('backend'); | ||
| $this->addTitleTab($this->translate(sprintf('Edit %s', $name))); | ||
|
|
||
| $form = new BackendConfigForm(); | ||
| $form->setConfig(Config::module('pdfexport')); | ||
| $form->setSection($name); | ||
|
|
||
| $form->on(Form::ON_SUBMIT, function () use ($form) { | ||
| Notification::success($this->translate('Updated print backend')); | ||
| $this->redirectNow('__CLOSE__'); | ||
| }); | ||
|
|
||
| $form->on(ConfigSectionForm::ON_DELETE, function () use ($form) { | ||
| Notification::success($this->translate('Print backend deleted')); | ||
| $this->redirectNow('__CLOSE__'); | ||
| }); | ||
|
|
||
| $form->handleRequest($this->getServerRequest()); | ||
|
|
||
| $this->addContent(HtmlString::create($form->render())); | ||
| } | ||
|
|
||
| public function createbackendAction(): void | ||
| { | ||
| $this->addTitleTab($this->translate(sprintf('Create Print Backend'))); | ||
|
|
||
| $form = new BackendConfigForm(); | ||
| $form->setConfig(Config::module('pdfexport')); | ||
| $form->setIsCreateForm(true); | ||
|
|
||
| $form->on(Form::ON_SUBMIT, function () { | ||
| Notification::success($this->translate('Created new print backend')); | ||
| $this->redirectNow('__CLOSE__'); | ||
| }); | ||
|
|
||
| $form->handleRequest($this->getServerRequest()); | ||
|
|
||
| $this->addContent($form); | ||
| } | ||
|
|
||
| protected function mergeTabs(Tabs $tabs): void | ||
| { | ||
| foreach ($tabs->getTabs() as $tab) { | ||
| $this->tabs->add($tab->getName(), $tab); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| <?php | ||
|
|
||
| // SPDX-FileCopyrightText: 2019 Icinga GmbH <https://icinga.com> | ||
| // SPDX-License-Identifier: GPL-3.0-or-later | ||
|
|
||
| namespace Icinga\Module\Pdfexport\Forms; | ||
|
|
||
| use Exception; | ||
| use Icinga\Module\Pdfexport\Backend\Chromedriver; | ||
| use Icinga\Module\Pdfexport\Backend\Geckodriver; | ||
| use Icinga\Module\Pdfexport\Backend\HeadlessChromeBackend; | ||
| use Icinga\Web\Form\ConfigSectionForm; | ||
| use ipl\Validator\CallbackValidator; | ||
|
|
||
| class BackendConfigForm extends ConfigSectionForm | ||
| { | ||
| public function assemble(): void | ||
| { | ||
| $this->addSectionNameElement(); | ||
|
|
||
| $this->addElement('number', 'priority', [ | ||
| 'label' => $this->translate('Priority'), | ||
| 'required' => true, | ||
| 'placeholder' => 100, | ||
| 'min' => 0, | ||
| 'description' => $this->translate('The priority of the backend. A lower priority will be used first.'), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This ordering seems counter-intuitive to me at first sight. @flourish86 What do you think?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the same order as menu items internally. To be fair afaik. it is the first time that a user would have to interact with the number directly. |
||
| ]); | ||
|
|
||
| $this->addElement('select', 'type', [ | ||
| 'label' => $this->translate('Type'), | ||
| 'multiOptions' => [ | ||
| '' => sprintf(' - %s - ', t('Please choose')), | ||
| 'chrome_webdriver' => t('Chrome WebDriver'), | ||
| 'firefox_webdriver' => t('Firefox WebDriver'), | ||
| 'remote_chrome' => t('Headless Chrome (Remote)'), | ||
| 'local_chrome' => t('Headless Chrome (Local)'), | ||
| ], | ||
| 'required' => true, | ||
| 'class' => 'autosubmit', | ||
| ]); | ||
|
|
||
| $type = $this->getPopulatedValue('type') ?? $this->getConfigValue('type'); | ||
|
|
||
| switch ($type) { | ||
| case 'remote_chrome': | ||
| $this->addElement('text', 'host', [ | ||
| 'label' => $this->translate('Host'), | ||
| 'description' => $this->translate('Host address of the server with the running web browser.'), | ||
| 'required' => true, | ||
| 'validators' => [ | ||
| new CallbackValidator(function ($value, CallbackValidator $validator) { | ||
| $port = $this->getValue('port') ?: 9222; | ||
|
|
||
| try { | ||
| $chrome = HeadlessChromeBackend::createRemote($value, $port); | ||
| $version = $chrome->getVersion(); | ||
| } catch (Exception $e) { | ||
| $validator->addMessage($e->getMessage()); | ||
| return false; | ||
| } | ||
|
|
||
| if ($version < HeadlessChromeBackend::MIN_SUPPORTED_CHROME_VERSION) { | ||
| $validator->addMessage(t( | ||
| 'Chrome/Chromium supporting headless mode required' | ||
| . ' which is provided since version %s. Version detected: %s', | ||
| )); | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| }), | ||
| ], | ||
| ]); | ||
|
|
||
| $this->addElement('number', 'port', [ | ||
| 'label' => $this->translate('Port'), | ||
| 'description' => $this->translate('Port of the chrome developer tools. (Default: 9222)'), | ||
| 'placeholder' => 9222, | ||
| 'min' => 1, | ||
| 'max' => 65535, | ||
| ]); | ||
|
|
||
| break; | ||
|
|
||
| case 'local_chrome': | ||
| $this->addElement('text', 'binary', [ | ||
| 'label' => $this->translate('Binary'), | ||
| 'placeholder' => '/usr/bin/google-chrome', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On my Fedora, it's sbin. While on it, I'd evaluate whether we can suggest Chromium instead.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I can't evaluate it myself, as) both browsers run into a Gateway Timeout. |
||
| 'description' => $this->translate('Path to the binary of the web browser.'), | ||
| 'validators' => [ | ||
| new CallbackValidator(function ($value, CallbackValidator $validator) { | ||
| if (empty($value)) { | ||
| return true; | ||
| } | ||
|
|
||
| try { | ||
| $chrome = (HeadlessChromeBackend::createLocal($value)); | ||
| $version = $chrome->getVersion(); | ||
| } catch (Exception $e) { | ||
| $validator->addMessage($e->getMessage()); | ||
| return false; | ||
| } | ||
|
|
||
| if ($version < HeadlessChromeBackend::MIN_SUPPORTED_CHROME_VERSION) { | ||
| $validator->addMessage(t( | ||
| 'Chrome/Chromium supporting headless mode required' | ||
| . ' which is provided since version %s. Version detected: %s', | ||
| )); | ||
| } | ||
|
|
||
| return true; | ||
| }), | ||
| ], | ||
| ]); | ||
|
|
||
| $this->addElement('checkbox', 'force_temp_storage', [ | ||
| 'label' => $this->translate('Use temp storage'), | ||
| 'description' => $this->translate( | ||
| 'Use temp storage to transfer the html to the local chrome instance.' | ||
| ), | ||
| 'checkedValue' => '1', | ||
| 'uncheckedValue' => '0', | ||
| ]); | ||
|
|
||
| break; | ||
|
|
||
| case 'firefox_webdriver': | ||
| case 'chrome_webdriver': | ||
| $this->addElement('text', 'host', [ | ||
| 'label' => $this->translate('Host'), | ||
| 'description' => $this->translate('Host address of the webdriver server'), | ||
| 'required' => true, | ||
| 'validators' => [ | ||
| new CallbackValidator(function ($value, CallbackValidator $validator) use ($type) { | ||
| $port = $this->getValue('port') ?: 4444; | ||
|
|
||
| try { | ||
| $url = "$value:$port"; | ||
| $backend = match ($type) { | ||
| 'chrome_webdriver' => new Chromedriver($url), | ||
| 'firefox_webdriver' => new Geckodriver($url), | ||
| default => throw new Exception("Invalid webdriver type $type"), | ||
| }; | ||
|
|
||
| if (! $backend->isSupported()) { | ||
| $validator->addMessage( | ||
| t('The webdriver server reports that it is unable to generate PDFs'), | ||
| ); | ||
| return false; | ||
| } | ||
| } catch (Exception $e) { | ||
| $validator->addMessage($e->getMessage()); | ||
| return false; | ||
| } | ||
| return true; | ||
| }), | ||
| ], | ||
| ]); | ||
|
|
||
| $this->addElement('number', 'port', [ | ||
| 'label' => $this->translate('Port'), | ||
| 'description' => $this->translate('Port of the webdriver instance. (Default: 4444)'), | ||
| 'placeholder' => 4444, | ||
| 'min' => 1, | ||
| 'max' => 65535, | ||
| ]); | ||
|
|
||
| break; | ||
| } | ||
|
|
||
| $this->addButtonElements(); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, /icingaweb2/config/userbackend displays vertical arrows next to multiple user backends and uses the order in the .ini file as prio. So the user doesn't have to manage such numbers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking about adding the drag-and-drop behavior like in kubernetes-web.
I would want that to be part of icingaweb or ipl-web first.