Skip to content

Commit

Permalink
Show error message on Elements with bad configured widget
Browse files Browse the repository at this point in the history
  • Loading branch information
maurofmferrao committed Sep 26, 2023
1 parent de55174 commit 95ff44c
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 20 deletions.
4 changes: 2 additions & 2 deletions lib/Controller/Layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ public function grid(Request $request, Response $response)
$module = $this->moduleFactory->getByType($widget->type);
} catch (NotFoundException $notFoundException) {
// This module isn't available, mark it as invalid.
$widget->isValid = 0;
$widget->isValid = false;
$widget->setUnmatchedProperty('moduleName', __('Invalid Module'));
$widget->setUnmatchedProperty('name', __('Invalid Module'));
$widget->setUnmatchedProperty('tags', []);
Expand Down Expand Up @@ -1504,7 +1504,7 @@ public function grid(Request $request, Response $response)
if (in_array('widget_validity', $embed)) {
$status = 0;
$layout->assessWidgetStatus($module, $widget, $status);
$widget->isValid = $status;
$widget->isValid = $status === 1;
}

// apply default transitions to a dynamic parameters on widget object.
Expand Down
2 changes: 1 addition & 1 deletion lib/Widget/IcsProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function fetchData(DataProviderInterface $dataProvider): WidgetProviderIn
// Do we have a feed configured?
$uri = $dataProvider->getProperty('uri');
if (empty($uri)) {
throw new InvalidArgumentException('Please enter a the URI to a valid ICS feed.', 'uri');
throw new InvalidArgumentException('Please enter the URI to a valid ICS feed.', 'uri');
}

// Create an ICal helper and pass it the contents of the file.
Expand Down
2 changes: 1 addition & 1 deletion lib/Widget/RssProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function fetchData(DataProviderInterface $dataProvider): WidgetProviderIn
{
$uri = $dataProvider->getProperty('uri');
if (empty($uri)) {
throw new InvalidArgumentException(__('Please enter a the URI to a valid RSS feed.'), 'uri');
throw new InvalidArgumentException(__('Please enter the URI to a valid RSS feed.'), 'uri');
}

$picoFeedLoggingEnabled = Environment::isDevMode();
Expand Down
17 changes: 4 additions & 13 deletions ui/src/editor-core/properties-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -528,21 +528,12 @@ PropertiesPanel.prototype.render = function(
// Check if we can use is repeat data
dataToRender.repeatDataActive = hasData;

// Check if we need to show the required elements error message
if (target.requiredElements && target.requiredElements.valid == false) {
const dataType = lD.common.getModuleByType(target.subType).dataType;

// Get element names for the missing elements
const requiredMissingElements =
target.requiredElements.missing.map((el) => {
const elTitle = lD.templateManager.templates[dataType][el].title;
return (elTitle != undefined) ? elTitle : el;
});
// Check required elements
const errorMessage = target.checkRequiredElements();

if (errorMessage != '') {
dataToRender.showErrorMessage = true;
dataToRender.errorMessage =
propertiesPanelTrans.requiredElementsMessage
.replace('%elements%', requiredMissingElements.join(', '));
dataToRender.errorMessage = errorMessage;
}
}

Expand Down
43 changes: 43 additions & 0 deletions ui/src/editor-core/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ const Widget = function(id, data, regionId = null, layoutObject = null) {
this.cachedData = {};
this.forceRecalculateData = false;

this.validateData = {};

this.validateRequiredElements = function() {
const moduleType = this.subType;
// Check if element is required
Expand Down Expand Up @@ -1135,10 +1137,24 @@ Widget.prototype.getData = function() {
data: sampleData,
meta: data?.meta || {},
};

// Save error to widget
self.validateData = {
sampleDataMessage: layoutEditorTrans.showingSampleData,
};

// If we have an error, add it to the validate data
if (data.success === false) {
self.validateData.errorMessage = data.message;
}

resolve(self.cachedData);
}
}
} else {
// Valid, so reset messages
self.validateData = {};

// Run onDataLoad/onParseData
Object.keys(modulesList).forEach(function(item) {
if (modulesList[item].type === self.subType
Expand Down Expand Up @@ -1194,6 +1210,33 @@ Widget.prototype.getData = function() {
return self.cachedDataPromise;
};

/**
* Update element map for this widget
* @return {string} error message
*/
Widget.prototype.checkRequiredElements = function() {
let errorMessage = '';
const self = this;

// Check if we need to show the required elements error message
if (self.requiredElements && self.requiredElements.valid == false) {
const dataType = lD.common.getModuleByType(self.subType).dataType;

// Get element names for the missing elements
const requiredMissingElements =
self.requiredElements.missing.map((el) => {
const elTitle = lD.templateManager.templates[dataType][el].title;
return (elTitle != undefined) ? elTitle : el;
});

errorMessage =
propertiesPanelTrans.requiredElementsMessage
.replace('%elements%', requiredMissingElements.join(', '));
}

return errorMessage;
};

/**
* Update element map for this widget
* @param {object} [element]
Expand Down
35 changes: 35 additions & 0 deletions ui/src/layout-editor/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,41 @@ Viewer.prototype.renderElementContent = function(
const elData = elementData?.data;
const meta = elementData?.meta;

// If parent widget isn't valid, replace error message
if (!$.isEmptyObject(parentWidget.validateData)) {
const $messageContainer = $elementContainer.find('.invalid-parent');
const errorArray = [$messageContainer.prop('title')];

// Required elements message
const requiredElementsErrorMessage =
parentWidget.checkRequiredElements();

(requiredElementsErrorMessage) &&
errorArray.push(
'<p>' +
requiredElementsErrorMessage +
'</p>');

// Default error message
(parentWidget.validateData.errorMessage) &&
errorArray.push(
'<p>' +
parentWidget.validateData.errorMessage +
'</p>');

(parentWidget.validateData.sampleDataMessage) &&
errorArray.push(
'<p class="sample-data">( ' +
parentWidget.validateData.sampleDataMessage +
' )</p>');

// Set title/tooltip
$messageContainer.tooltip('dispose')
.prop('title', '<div class="custom-tooltip">' +
errorArray.join('') + '</div>');
$messageContainer.tooltip();
}

// Check all data elements and make replacements
for (const key in elData) {
if (elData.hasOwnProperty(key)) {
Expand Down
15 changes: 15 additions & 0 deletions ui/src/style/layout-editor.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1903,3 +1903,18 @@ body[layout-editor-fs] .moveable-control-box {
color: $xibo-color-accent !important;
font-size: 1rem !important;
}

/* Custom tooltip */
.custom-tooltip {
text-align: left;
color: $xibo-color-neutral-0;
line-height: 1.2;

p {
margin: 0.3rem 0;
}

.sample-data {
color: $xibo-color-tertiary;
}
}
2 changes: 1 addition & 1 deletion ui/src/templates/viewer-element-content.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
{{/neq}}

{{#if invalidParent}}
<div class="invalid-parent" title="{{trans.invalidWidget}}">
<div class="invalid-parent" data-html="true" title="{{trans.invalidWidget}}">
<i class="fa fa-warning"></i>
</div>
{{/if}}
Expand Down
2 changes: 1 addition & 1 deletion views/common.twig
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@
left: "{{ "Left" |trans }}",
scale: "{{ "Scale"|trans }}",
layer: "{{ "Layer"|trans }}",
invalidWidget: "{{ "This widget needs to be configured before it will be shown"|trans }}",
invalidWidget: "{{ "This widget needs to be configured before it will be shown."|trans }}",
requiredElementsMessage: "{{ "This widget needs to have at least one of the following elements: %elements%." |trans }}",
dataSlot: "{{ "Data Slot"|trans }}",
dataSlotHelpText: "{{ "When there are more than one of the same element for a widget you can set the slot for each element. For example with two of the same element you'd have data slot 1 and data slot 2. If 10 items were returned slot 1 would receive items 1,3,5,7,9 and slot 2 would receive items 2,4,6,8,19."|trans }}",
Expand Down
3 changes: 2 additions & 1 deletion views/layout-designer-page.twig
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@
unlockMessage: "{% trans "The current layout will be unlocked to other users. You will also be redirected to the Layouts page" %}",
viewModeTitle: "{% trans "View" %}",
actions: "{% trans "Actions" %}",
welcomeModalMessage: "{% trans "This is published and cannot be edited. You can checkout for editing below, or continue to view it in a read only mode." %}"
welcomeModalMessage: "{% trans "This is published and cannot be edited. You can checkout for editing below, or continue to view it in a read only mode." %}",
showingSampleData: "{% trans "Showing sample data" %}",
};
var viewerTrans = {
Expand Down

0 comments on commit 95ff44c

Please sign in to comment.