Commit 0e01a866 authored by Jochen Roth's avatar Jochen Roth Committed by Benni Mack
Browse files

[BUGFIX] Fix dashboard error when event is not initialized

When trying to add a widget when events not applied caused
the add widget button to throw "undefined array key 'widget'".

This is fixed by removing the url from the affected buttons.
Tests have also been added for "create dashboard", "add widget",
"delete dashboard" and "remove widget".

Resolves: #94396
Releases: master
Change-Id: Ifa64da17c901145016f22a475e655ad475e46c37
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/69542

Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent 5932bdbd
......@@ -42,6 +42,11 @@ class WidgetSelector {
};
Modal.advanced(configuration);
}).delegateTo(document, this.selector);
// Display button only if all initialized
document.querySelectorAll(this.selector).forEach((item) => {
item.classList.remove('hide');
})
}
}
......
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\Tests\Acceptance\Backend\Info;
use TYPO3\CMS\Core\Tests\Acceptance\Support\BackendTester;
use TYPO3\CMS\Core\Tests\Acceptance\Support\Helper\ModalDialog;
/**
* Tests concerning Reports Module
*/
class DashboardModuleCest
{
protected static string $defaultDashboardTitle = 'My Dashboard';
protected static string $customDashboardTitle = 'My Custom Dashboard';
protected static string $dashboardActiveSelector = '.dashboard-tab--active';
protected static string $widgetTitle = 'TYPO3 news';
protected static string $widgetTitleSelector = '.widget-content-title';
/**
* @param BackendTester $I
*/
public function _before(BackendTester $I)
{
$I->useExistingSession('admin');
$I->click('#dashboard');
$I->switchToContentFrame();
}
/**
* @param BackendTester $I
*/
public function seeInitialDashboardAndWidgets(BackendTester $I)
{
$I->see(self::$defaultDashboardTitle, self::$dashboardActiveSelector);
$I->see('About TYPO3', self::$widgetTitleSelector);
$I->see(self::$widgetTitle, self::$widgetTitleSelector);
$I->see('Getting Started with TYPO3', self::$widgetTitleSelector);
}
/**
* @param BackendTester $I
* @param ModalDialog $modalDialog
*/
public function createCustomDashboardAndWidgets(BackendTester $I, ModalDialog $modalDialog)
{
// Create Dashboard
$I->click('.dashboard-button-tab-add');
$modalDialog->canSeeDialog();
$I->fillField('#dashboardModalAdd-title', self::$customDashboardTitle);
$I->click('button[name="save"]', ModalDialog::$openedModalButtonContainerSelector);
$I->switchToContentFrame();
$I->see(self::$customDashboardTitle, self::$dashboardActiveSelector);
// Add widget
$I->waitForElementVisible('.js-dashboard-addWidget');
$I->click('.js-dashboard-addWidget');
$modalDialog->canSeeDialog();
$I->click('#dashboard-widgetgroup-tab-news');
$I->click(self::$widgetTitle, ModalDialog::$openedModalSelector);
$I->switchToContentFrame();
$I->see(self::$widgetTitle, self::$widgetTitleSelector);
}
/**
* @depends createCustomDashboardAndWidgets
* @param BackendTester $I
* @param ModalDialog $modalDialog
*/
public function deleteDashboardAndWidgets(BackendTester $I, ModalDialog $modalDialog)
{
// Delete widget
$I->click(self::$customDashboardTitle, '.dashboard-tabs');
$I->waitForElementVisible('div[data-widget-key="t3news"] .widget-content-title');
$I->click('.js-dashboard-remove-widget');
$modalDialog->canSeeDialog();
$I->click('button[name="delete"]', ModalDialog::$openedModalButtonContainerSelector);
$I->switchToContentFrame();
$I->seeElement('.dashboard-empty-content');
// Delete custom dashboard
$I->click('.js-dashboard-delete');
$modalDialog->canSeeDialog();
$I->click('button[name="delete"]', ModalDialog::$openedModalButtonContainerSelector);
$I->dontSee(self::$customDashboardTitle, self::$dashboardActiveSelector);
}
}
......@@ -34,6 +34,7 @@ use TYPO3\CMS\Dashboard\DashboardInitializationService;
use TYPO3\CMS\Dashboard\DashboardPresetRegistry;
use TYPO3\CMS\Dashboard\DashboardRepository;
use TYPO3\CMS\Dashboard\WidgetGroupInitializationService;
use TYPO3\CMS\Extbase\Mvc\Controller\Exception\RequiredArgumentMissingException;
use TYPO3\CMS\Extbase\Mvc\View\ViewInterface;
use TYPO3\CMS\Fluid\View\StandaloneView;
......@@ -195,19 +196,21 @@ class DashboardController extends AbstractController
* @param ServerRequestInterface $request
* @return ResponseInterface
* @throws RouteNotFoundExceptionAlias
* @throws RequiredArgumentMissingException
*/
public function addWidgetAction(ServerRequestInterface $request): ResponseInterface
{
$parameters = $request->getQueryParams();
$widgetKey = $parameters['widget'];
$widgetKey = (string)($request->getQueryParams()['widget'] ?? '');
if ($widgetKey) {
$widgets = $this->currentDashboard->getWidgetConfig();
$hash = sha1($widgetKey . '-' . time());
$widgets[$hash] = ['identifier' => $widgetKey];
$this->dashboardRepository->updateWidgetConfig($this->currentDashboard, $widgets);
if ($widgetKey === '') {
throw new RequiredArgumentMissingException('Argument "widget" not set.', 1624436360);
}
$widgets = $this->currentDashboard->getWidgetConfig();
$hash = sha1($widgetKey . '-' . time());
$widgets[$hash] = ['identifier' => $widgetKey];
$this->dashboardRepository->updateWidgetConfig($this->currentDashboard, $widgets);
$route = $this->uriBuilder->buildUriFromRoute('dashboard', ['action' => 'main']);
return new RedirectResponse($route);
}
......
......@@ -63,19 +63,19 @@
<div class="dashboard-empty-content">
<h3><f:translate key="dashboard.empty.content.title" extensionName="dashboard" /></h3>
<p><f:translate key="dashboard.empty.content.description" extensionName="dashboard" /></p>
<a href="{addWidgetUri}" class="js-dashboard-addWidget dashboard-button" title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-modal-title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-button-close-text="{f:translate(key: 'widget.add.button.close', extensionName: 'dashboard')}" data-button-ok-text="{f:translate(key: 'widget.add.button.ok', extensionName: 'dashboard')}">
<button class="js-dashboard-addWidget btn dashboard-button hide" title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-modal-title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-button-close-text="{f:translate(key: 'widget.add.button.close', extensionName: 'dashboard')}" data-button-ok-text="{f:translate(key: 'widget.add.button.ok', extensionName: 'dashboard')}">
<span class="dashboard-button-icon"><core:icon identifier="actions-add" alternativeMarkupIdentifier="inline" /></span>
<span class="dashboard-button-text"><f:translate key="dashboard.empty.content.button" extensionName="dashboard" /></span>
</a>
</button>
</div>
</div>
</f:else>
</f:if>
<div class="dashboard-add-item">
<a href="{addWidgetUri}" class="js-dashboard-addWidget dashboard-button dashboard-button-add" title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-modal-title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-button-close-text="{f:translate(key: 'widget.add.button.close', extensionName: 'dashboard')}" data-button-ok-text="{f:translate(key: 'widget.add.button.ok', extensionName: 'dashboard')}">
<button class="js-dashboard-addWidget btn dashboard-button dashboard-button-add hide" title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-modal-title="{f:translate(key: 'widget.add', extensionName: 'dashboard')}" data-button-close-text="{f:translate(key: 'widget.add.button.close', extensionName: 'dashboard')}" data-button-ok-text="{f:translate(key: 'widget.add.button.ok', extensionName: 'dashboard')}">
<core:icon identifier="actions-add" alternativeMarkupIdentifier="inline" /><span class="sr-only"><f:translate key="widget.add" extensionName="dashboard"/></span>
</a>
</button>
</div>
<div id="widgetSelector" class="hide">
......
......@@ -10,4 +10,4 @@
*
* The TYPO3 project - inspiring people to share!
*/
var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","jquery","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Enum/Severity","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,i,a,s,d){"use strict";i=__importDefault(i);return new class{constructor(){this.selector=".js-dashboard-addWidget",this.initialize()}initialize(){new d("click",(function(e){e.preventDefault();const t={type:a.types.default,title:this.dataset.modalTitle,size:a.sizes.medium,severity:s.SeverityEnum.notice,content:i.default(document.getElementById("widgetSelector").innerHTML),additionalCssClasses:["dashboard-modal"],callback:e=>{e.on("click","a.dashboard-modal-item-block",t=>{e.trigger("modal-dismiss")})}};a.advanced(t)})).delegateTo(document,this.selector)}}}));
\ No newline at end of file
var __importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};define(["require","exports","jquery","TYPO3/CMS/Backend/Modal","TYPO3/CMS/Backend/Enum/Severity","TYPO3/CMS/Core/Event/RegularEvent"],(function(e,t,i,a,s,l){"use strict";i=__importDefault(i);return new class{constructor(){this.selector=".js-dashboard-addWidget",this.initialize()}initialize(){new l("click",(function(e){e.preventDefault();const t={type:a.types.default,title:this.dataset.modalTitle,size:a.sizes.medium,severity:s.SeverityEnum.notice,content:i.default(document.getElementById("widgetSelector").innerHTML),additionalCssClasses:["dashboard-modal"],callback:e=>{e.on("click","a.dashboard-modal-item-block",t=>{e.trigger("modal-dismiss")})}};a.advanced(t)})).delegateTo(document,this.selector),document.querySelectorAll(this.selector).forEach(e=>{e.classList.remove("hide")})}}}));
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment