moduleDashlets = Modules\DashletManager::getDashlets(); $this->setRedirectUrl((string) Url::fromPath(Dashboard::BASE_ROUTE)); $this->setAction($this->getRedirectUrl() . '/setup-dashboard'); } /** * Dump all module dashlets which are not selected by the user * * @param bool $strict Whether to match the populated value of the dashlet against a 'y' * * @return void */ protected function dumpArbitaryDashlets(bool $strict = true): void { $chosenDashlets = []; foreach ($this->moduleDashlets as $module => $dashlets) { /** @var Dashlet $dashlet */ foreach ($dashlets as $dashlet) { $element = bin2hex($dashlet->getUuid()); if ($this->getPopulatedValue($element) === 'y' || (! $strict && $this->getPopulatedValue($element))) { $title = $this->getPopulatedValue($element); $url = $this->getPopulatedValue($element . '_url'); $description = $this->getPopulatedValue($element . '_description'); if (! $strict && $title && $url) { $dashlet ->setUrl($url) ->setName($title . '(' . $module . ')') ->setTitle($title) ->setDescription($description); } $chosenDashlets[$module][$dashlet->getName()] = $dashlet; } } if (isset($chosenDashlets[$module]) && ! $this->customDashletAlreadyExists) { // This should never ever happen, but hey, it never harms to play it save!! $this->customDashletAlreadyExists = array_key_exists( $this->getPopulatedValue('dashlet'), $chosenDashlets[$module] ); } } $this->moduleDashlets = $chosenDashlets; } /** * Assemble the next page of the modal view * * @return void */ protected function assembleNextPage() { $strict = $this->isUpdating() || $this->getPopulatedValue('btn_next') || ! $this->hasBeenSent(); $this->dumpArbitaryDashlets($strict); $this->assembleNextPageDashboardPart(); $this->assembleNexPageDashletPart(); } /** * Assemble the browsed module dashlets on the initial view * * @return void */ protected function assembleSelectDashletView() { if ($this->getPopulatedValue('btn_next')) { return; } $emptyDashlet = new EmptyDashlet(); $emptyDashlet->setCheckBox($this->createElement('checkbox', 'custom_url', ['class' => 'sr-only'])); $emptyList = HtmlElement::create('ul', ['class' => 'dashlet-item-list'], $emptyDashlet); $listControl = $this->createFormListControls(); $listControl->addHtml($emptyList); $this->addHtml($listControl); foreach ($this->moduleDashlets as $module => $dashlets) { $listControl = $this->createFormListControls(ucfirst($module)); $list = HtmlElement::create('ul', ['class' => 'dashlet-item-list']); /** @var Dashlet $dashlet */ foreach ($dashlets as $dashlet) { $multi = new DashletListMultiSelect($dashlet); $multi->setCheckBox($this->createElement( 'checkbox', bin2hex($dashlet->getUuid()), ['class' => 'sr-only'] )); $list->addHtml($multi); } $this->addHtml($listControl->addHtml($list)); } } /** * Assemble the dashboard part of elements on the next page * * @return void */ protected function assembleNextPageDashboardPart() { $this->addElement('text', 'pane', [ 'required' => true, 'label' => t('Dashboard Title'), 'description' => t('Enter a title for the new dashboard you want to add the dashlets to.') ]); } /** * Assemble the dashlet part of elements on the next page * * @return void */ protected function assembleNexPageDashletPart() { if ((empty($this->moduleDashlets) || $this->getPopulatedValue('custom_url') === 'y') && ! $this->isUpdating()) { $this->addHtml(HtmlElement::create('hr')); $this->assembleDashletElements(); } foreach ($this->moduleDashlets as $_ => $dashlets) { /** @var Dashlet $dashlet */ foreach ($dashlets as $dashlet) { $this->addHtml(HtmlElement::create('h3', null, t($dashlet->getTitle()))); $elementId = bin2hex($dashlet->getUuid()); if ($this->getPopulatedValue('btn_next')) { $this->clearPopulatedValue($elementId); } $this->addElement('text', $elementId, [ 'required' => true, 'label' => t('Dashlet Title'), 'value' => $dashlet->getTitle(), 'description' => t('Enter a title for the dashlet'), ]); $this->addElement('textarea', $elementId . '_url', [ 'required' => true, 'label' => t('Url'), 'value' => $dashlet->getUrl()->getRelativeUrl(), 'description' => t( 'Enter url to be loaded in the dashlet. You can paste the full URL, including filters.' ) ]); $this->addElement('textarea', $elementId . '_description', [ 'label' => t('Description'), 'value' => $dashlet->getDescription(), 'description' => t('Enter description for the dashlet.') ]); } } } protected function assembleDashletElements() { $this->addElement('hidden', 'custom_url', ['required' => false, 'value' => 'y']); $this->addElement('text', 'dashlet', [ 'required' => true, 'label' => t('Dashlet Title'), 'placeholder' => t('Enter a dashlet title'), 'description' => t('Enter a title for the dashlet.'), ]); $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.' ), ]); $this->addElement('textarea', 'description', [ 'label' => t('Description'), 'placeholder' => t('Enter dashlet description'), 'description' => t('Enter description for the dashlet.'), ]); } protected function assemble() { if ($this->getPopulatedValue('btn_next')) { // Configure Dashlets $submitButtonLabel = t('Add Dashlets'); $this->assembleNextPage(); } else { $submitButtonLabel = t('Next'); $this->assembleSelectDashletView(); } $submitButton = $this->registerSubmitButton($submitButtonLabel); if (! $this->getPopulatedValue('btn_next')) { $submitButton ->setName('btn_next') ->getAttributes()->add('class', 'autosubmit'); } $formControls = $this->createFormControls(); $formControls->addHtml($submitButton, $this->createCancelButton()); $this->addHtml($formControls); } protected function onSuccess() { if ($this->getPopulatedValue('submit')) { $conn = DBUtils::getConn(); $pane = new Pane($this->getPopulatedValue('pane')); $home = $this->dashboard->getEntry(DashboardHome::DEFAULT_HOME); $conn->beginTransaction(); try { $this->dashboard->manageEntry($home); $home->manageEntry($pane); $this->dumpArbitaryDashlets(false); if (($name = $this->getPopulatedValue('dashlet')) && ($url = $this->getPopulatedValue('url'))) { if ($this->customDashletAlreadyExists) { Notification::error(sprintf( t('Failed to create custom Dashlet! The selected module Dashlet(s) contains Dashlet "%s"'), $name )); return; } $dashlet = new Dashlet($name, $url, $pane); $pane->manageEntry($dashlet); } $pane->manageEntry($this->moduleDashlets); $conn->commitTransaction(); } catch (\Exception $err) { $conn->rollBackTransaction(); Logger::error('Unable to create new Dashlet(s). An unexpected error occurred: %s', $err); Notification::error(t('Failed to create new Dashlet(s). Please check the logs for details!')); return; } $this->requestSucceeded = true; $count = $pane->countEntries(); $dashlet = $pane->getEntries(); $dashlet = end($dashlet); Notification::success(sprintf( tp('Added Dashlet %s successfully', 'Added %d Dashlets successfully', $count), $count === 1 ? $dashlet->getTitle() : $count )); } } /** * Create form list controls (can be collapsible if you want) * * @param ?string $title * * @return ValidHtml */ protected function createFormListControls(string $title = null): ValidHtml { $controlGroup = HtmlElement::create('div', ['class' => 'control-group']); if ($title === null) { return $controlGroup; } $details = HtmlElement::create('details', [ 'class' => ['dashboard-list-control', 'collapsible'], 'data-no-persistence' => true ]); $summary = HtmlElement::create('summary', ['class' => 'collapsible-header']); $summary->addHtml( new Icon('angle-right', ['class' => 'expand-icon', 'title' => t('Expand')]), new Icon('angle-down', ['class' => 'collapse-icon', 'title' => t('Collapse')]), Text::create($title) ); $details->addHtml($summary); $details->prependWrapper($controlGroup); return $details; } }