Commit aaa7a5a4 authored by Mikel Martín Corrales's avatar Mikel Martín Corrales
Browse files

MDL-72565 reportbuilder: Add 'Card view' settings to custom reports

- Create a new 'settings' column in reportbuilder_report table and provide an API to manage it
- Add new card view settings to custom reports
parent f2582cc8
......@@ -48,6 +48,11 @@ $string['audiencedeleted'] = 'Deleted audience \'{$a}\'';
$string['audiencemultiselectpostfix'] = '{$a->elements} plus {$a->morecount} more';
$string['audiencenotsaved'] = 'Audience not saved';
$string['audiencesaved'] = 'Audience saved';
$string['cardview'] = 'Card view';
$string['cardview_help'] = 'Card view allows you to define the layout of your report when viewed on narrow devices. Columns will collapse beyond the limit set here, with a toggle to expand the card to view all report data.';
$string['cardviewfirstcolumntitle'] = 'First column title';
$string['cardviewsettingssaved'] = 'Card view settings saved';
$string['cardviewvisiblecolumns'] = 'Columns visible';
$string['columnadded'] = 'Added column \'{$a}\'';
$string['columnaggregated'] = 'Aggregated column \'{$a}\'';
$string['columndeleted'] = 'Deleted column \'{$a}\'';
......
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="lib/db" VERSION="20211011" COMMENT="XMLDB file for core Moodle tables"
<XMLDB PATH="lib/db" VERSION="20211106" COMMENT="XMLDB file for core Moodle tables"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../lib/xmldb/xmldb.xsd"
>
......@@ -4387,6 +4387,7 @@
<FIELD NAME="source" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="type" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
<FIELD NAME="conditiondata" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="settingsdata" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="area" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
......
......@@ -3130,5 +3130,20 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2021110800.02);
}
if ($oldversion < 2021110800.03) {
// Define field settingsdata to be added to reportbuilder_report.
$table = new xmldb_table('reportbuilder_report');
$field = new xmldb_field('settingsdata', XMLDB_TYPE_TEXT, null, null, null, null, null, 'conditiondata');
// Conditionally launch add field settingsdata.
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Main savepoint reached.
upgrade_main_savepoint(true, 2021110800.03);
}
return true;
}
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
File suppressed by a .gitattributes entry or the file's encoding is unsupported.
......@@ -32,6 +32,7 @@ import {init as columnsEditorInit} from 'core_reportbuilder/local/editor/columns
import {init as conditionsEditorInit} from 'core_reportbuilder/local/editor/conditions';
import {init as filtersEditorInit} from 'core_reportbuilder/local/editor/filters';
import {init as sortingEditorInit} from 'core_reportbuilder/local/editor/sorting';
import {init as cardviewEditorInit} from 'core_reportbuilder/local/editor/card_view';
import {getReport} from 'core_reportbuilder/local/repository/reports';
let initialized = false;
......@@ -44,6 +45,7 @@ export const init = () => {
conditionsEditorInit(initialized);
filtersEditorInit(initialized);
sortingEditorInit(initialized);
cardviewEditorInit(initialized);
// Ensure we only add our listeners once (can be called multiple times by mustache template).
if (initialized) {
......
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Report builder card view editor
*
* @module core_reportbuilder/local/editor/card_view
* @copyright 2021 Mikel Martín <mikel@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
"use strict";
import DynamicForm from 'core_form/dynamicform';
import {add as addToast} from 'core/toast';
import {get_string as getString} from "core/str";
import {subscribe as subscribe} from 'core/pubsub';
import Notification from 'core/notification';
import * as reportEvents from 'core_reportbuilder/local/events';
import * as reportSelectors from 'core_reportbuilder/local/selectors';
let cardViewForm = null;
/**
* Initialise card view form, must be called on each init because the form container is re-created when switching editor modes
*/
const initCardViewForm = () => {
const cardViewFormContainer = document.querySelector(reportSelectors.regions.settingsCardView);
if (!cardViewFormContainer) {
return;
}
cardViewForm = new DynamicForm(cardViewFormContainer, '\\core_reportbuilder\\form\\card_view');
cardViewForm.addEventListener(cardViewForm.events.FORM_SUBMITTED, (event) => {
event.preventDefault();
getString('cardviewsettingssaved', 'core_reportbuilder')
.then(addToast)
.catch(Notification.exception);
});
};
/**
* Initialise module
*
* @param {Boolean} initialized Ensure we only add our listeners once
*/
export const init = (initialized) => {
initCardViewForm();
if (initialized) {
return;
}
// Update form each time a column is added or removed to the custom report.
subscribe(reportEvents.publish.reportColumnsUpdated, () => {
const reportElement = document.querySelector(reportSelectors.regions.report);
cardViewForm.load({reportid: reportElement.dataset.reportId});
});
};
......@@ -52,6 +52,7 @@ const SELECTORS = {
audienceEmptyMessage: '[data-region=no-instances-message]',
audienceDescription: '[data-region=audience-description]',
audienceNotSavedLabel: '[data-region=audience-not-saved]',
settingsCardView: '[data-region="settings-cardview"]',
},
actions: {
reportActionPopup: '[data-action="report-action-popup"]',
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder\external;
use core_reportbuilder\form\card_view;
use renderer_base;
use core\external\exporter;
use core_reportbuilder\local\report\base;
/**
* Custom report card view exporter class
*
* @package core_reportbuilder
* @copyright 2021 Mikel Martín <mikel@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class custom_report_card_view_exporter extends exporter {
/**
* Return a list of objects that are related to the exporter
*
* @return array
*/
protected static function define_related(): array {
return [
'report' => base::class,
];
}
/**
* Return the list of additional properties for read structure and export
*
* @return array[]
*/
protected static function define_other_properties(): array {
return [
'form' => [
'type' => PARAM_RAW,
'optional' => true,
],
'helpicon' => [
'type' => PARAM_RAW,
'optional' => true,
],
];
}
/**
* Get the additional values to inject while exporting
*
* @param renderer_base $output
* @return array
*/
protected function get_other_values(renderer_base $output): array {
/** @var base $report */
$report = $this->related['report'];
$reportid = $report->get_report_persistent()->get('id');
$reportsettings = $report->get_settings_values();
$cardviewsettings = [
'showfirsttitle' => $reportsettings['cardview_showfirsttitle'] ?? 0,
'visiblecolumns' => $reportsettings['cardview_visiblecolumns'] ?? 1,
];
$cardviewform = new card_view(null, null, 'post', '', [], true,
array_merge(['reportid' => $reportid], $cardviewsettings));
$cardviewform->set_data_for_dynamic_submission();
return [
'form' => $cardviewform->render(),
'helpicon' => $output->help_icon('cardview', 'core_reportbuilder'),
];
}
}
......@@ -93,6 +93,7 @@ class custom_report_exporter extends persistent_exporter {
'conditions' => ['type' => custom_report_conditions_exporter::read_properties_definition()],
'filters' => ['type' => custom_report_filters_exporter::read_properties_definition()],
'sorting' => ['type' => custom_report_columns_sorting_exporter::read_properties_definition()],
'cardview' => ['type' => custom_report_card_view_exporter::read_properties_definition()],
'filtersapplied' => ['type' => PARAM_INT],
'filterspresent' => ['type' => PARAM_BOOL],
'filtersform' => [
......@@ -147,6 +148,8 @@ class custom_report_exporter extends persistent_exporter {
$filters = (array) $filtersexporter->export($output);
$sortingexporter = new custom_report_columns_sorting_exporter(null, ['report' => $report]);
$sorting = (array) $sortingexporter->export($output);
$cardviewexporter = new custom_report_card_view_exporter(null, ['report' => $report]);
$cardview = (array) $cardviewexporter->export($output);
}
return [
......@@ -155,6 +158,7 @@ class custom_report_exporter extends persistent_exporter {
'conditions' => $conditions ?? [],
'filters' => $filters ?? [],
'sorting' => $sorting ?? [],
'cardview' => $cardview ?? [],
'filtersapplied' => $report->get_applied_filter_count(),
'filterspresent' => $filterspresent,
'filtersform' => $filtersform,
......
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
declare(strict_types=1);
namespace core_reportbuilder\form;
use context;
use moodle_url;
use core_form\dynamic_form;
use core_reportbuilder\manager;
use core_reportbuilder\permission;
use core_reportbuilder\local\report\base;
use core_reportbuilder\local\models\report;
use core_reportbuilder\local\models\column;
/**
* Card view dynamic form
*
* @package core_reportbuilder
* @copyright 2021 Mikel Martín <mikel@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class card_view extends dynamic_form {
/**
* Return instance of the report using the card view form
*
* @return base
*/
private function get_report(): base {
$report = new report($this->optional_param('reportid', 0, PARAM_INT));
$parameters = (array) json_decode($this->optional_param('parameters', '', PARAM_RAW));
return manager::get_report_from_persistent($report, $parameters);
}
/**
* Returns context where this form is used
*
* @return context
*/
protected function get_context_for_dynamic_submission(): context {
return $this->get_report()->get_context();
}
/**
* Check if current user has access to this form, otherwise throw exception
*/
public function check_access_for_dynamic_submission(): void {
permission::require_can_edit_report($this->get_report()->get_report_persistent());
}
/**
* Store the conditions values and operators
*
* @return bool
*/
public function process_dynamic_submission(): bool {
$values = $this->get_data();
$settings = [
'cardview_showfirsttitle' => (int)$values->showfirsttitle,
// Minimum value for 'cardview_visiblecolumns' should be 1.
'cardview_visiblecolumns' => max((int)$values->visiblecolumns, 1)
];
return $this->get_report()->set_settings_values($settings);
}
/**
* Load in existing data as form defaults
*/
public function set_data_for_dynamic_submission(): void {
$report = $this->get_report();
$totalcolumns = column::count_records(['reportid' => $report->get_report_persistent()->get('id')]);
$settings = $report->get_settings_values();
$defaults = [
// Maximum value for 'cardview_visiblecolumns' should be the report total number of columns.
'visiblecolumns' => min($settings['cardview_visiblecolumns'] ?? 1, $totalcolumns),
'showfirsttitle' => $settings['cardview_showfirsttitle'] ?? 0,
];
$this->set_data(array_merge($defaults, $this->_ajaxformdata));
}
/**
* Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX
*
* @return moodle_url
*/
protected function get_page_url_for_dynamic_submission(): moodle_url {
return new moodle_url('/reportbuilder/edit.php');
}
/**
* Card view form definition
*/
public function definition(): void {
$mform = $this->_form;
$reportid = $this->optional_param('reportid', 0, PARAM_INT);
$totalcolumns = column::count_records(['reportid' => $reportid]);
$visibilityarray = [];
// Generate select options from 1 to report total number of columns.
for ($i = 1; $i <= max($totalcolumns, 1); $i++) {
$visibilityarray[$i] = $i;
}
$mform->addElement('hidden', 'reportid');
$mform->setType('reportid', PARAM_INT);
$mform->addElement('select', 'visiblecolumns', get_string('cardviewvisiblecolumns', 'core_reportbuilder'),
$visibilityarray);
$mform->setType('visiblecolumns', PARAM_INT);
$mform->addElement('selectyesno', 'showfirsttitle', get_string('cardviewfirstcolumntitle', 'core_reportbuilder'));
$mform->setType('showfirsttitle', PARAM_BOOL);
$mform->disable_form_change_checker();
$this->add_action_buttons(false);
}
}
......@@ -65,6 +65,11 @@ class report extends persistent {
'null' => NULL_ALLOWED,
'default' => null,
],
'settingsdata' => [
'type' => PARAM_RAW,
'null' => NULL_ALLOWED,
'default' => null,
],
'contextid' => [
'type' => PARAM_INT,
'default' => static function(): int {
......
......@@ -496,6 +496,31 @@ abstract class base {
return (array) json_decode($conditions);
}
/**
* Set the settings values of the report
*
* @param array $values
* @return bool
*/
final public function set_settings_values(array $values): bool {
$currentsettings = $this->get_settings_values();
$settings = array_merge($currentsettings, $values);
$this->report->set('settingsdata', json_encode($settings))
->save();
return true;
}
/**
* Get the settings values of the report
*
* @return array
*/
final public function get_settings_values(): array {
$settings = (string) $this->report->get('settingsdata');
return (array) json_decode($settings);
}
/**
* Adds a filter to the report
*
......
......@@ -106,6 +106,16 @@
{{/body}}
{{/ core_reportbuilder/toggle_card }}
{{< core_reportbuilder/toggle_card }}
{{$collapsed}}collapsed{{/collapsed}}
{{$id}}settingscardview{{/id}}
{{$header}}{{#str}} cardview, core_reportbuilder {{/str}}{{/header}}
{{$helpicon}}{{{cardview.helpicon}}}{{/helpicon}}
{{$body}}
{{> core_reportbuilder/local/settings/card_view}}
{{/body}}
{{/ core_reportbuilder/toggle_card }}
</div>
</div>
</div>
......
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_reportbuilder/local/settings/card_view
Template for custom report card view settings area
Example context (json):
{
"form": "form"
}
}}
<div class="px-4 pt-4 pb-0" data-region="settings-cardview">
{{#cardview}}
{{{form}}}
{{/cardview}}
</div>
......@@ -31,14 +31,14 @@ Feature: Configure access to reports based on intended audience
Then I click on "Add audience 'Manually added users'" "link"
And I should see "Added audience 'Manually added users'"
And I set the field "Add users manually" to "User 1,User 3"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
And I should see "Audience saved"
And I should see "User 1"
And I should not see "User 2"
And I should see "User 3"
And I should not see "Add an audience to this report"
And I click on the "Access" dynamic tab
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I should see "User 1" in the "[role=tabpanel].active" "css_element"
And I should not see "User 2" in the "[role=tabpanel].active" "css_element"
And I should see "User 3" in the "[role=tabpanel].active" "css_element"
......@@ -55,12 +55,12 @@ Feature: Configure access to reports based on intended audience
When I click on "Add audience 'Assigned system role'" "link"
And I should see "Added audience 'Assigned system role'"
And I set the field "Select a role" to "Test role"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
Then I should see "Audience saved"
And I should see "Test role"
And I should not see "Add an audience to this report"
And I click on the "Access" dynamic tab
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I should not see "User 1" in the "[role=tabpanel].active" "css_element"
And I should see "User 2" in the "[role=tabpanel].active" "css_element"
And I should not see "User 3" in the "[role=tabpanel].active" "css_element"
......@@ -77,12 +77,12 @@ Feature: Configure access to reports based on intended audience
When I click on "Add audience 'Member of cohort'" "link"
And I should see "Added audience 'Member of cohort'"
And I set the field "Select members from cohort" to "Cohort1"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
Then I should see "Audience saved"
And I should see "Cohort1"
And I should not see "Add an audience to this report"
And I click on the "Access" dynamic tab
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I should not see "User 1" in the "[role=tabpanel].active" "css_element"
And I should not see "User 2" in the "[role=tabpanel].active" "css_element"
And I should see "User 3" in the "[role=tabpanel].active" "css_element"
......@@ -98,7 +98,8 @@ Feature: Configure access to reports based on intended audience
Given I am on the "My report" "reportbuilder > Editor" page logged in as "admin"
And I click on the "Audience" dynamic tab
And I click on "Add audience 'All users'" "link"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
When I click on "Delete audience 'All users'" "button"
And I click on "Delete" "button" in the "Delete audience 'All users'" "dialogue"
Then I should see "Deleted audience 'All users'"
......@@ -112,12 +113,12 @@ Feature: Configure access to reports based on intended audience
And I should see "Add an audience to this report"
Then I click on "Add audience 'Manually added users'" "link"
And I set the field "Add users manually" to "User 1,User 3"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
And I press "Edit audience 'Manually added users'"
And I set the field "Add users manually" to "User 2"
And I press "Save changes"
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
And I should see "Audience saved"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I should not see "User 1" in the "[role=tabpanel].active" "css_element"
And I should see "User 2" in the "[role=tabpanel].active" "css_element"
And I should not see "User 3" in the "[role=tabpanel].active" "css_element"
......@@ -155,7 +156,8 @@ Feature: Configure access to reports based on intended audience
And I should see "Add an audience to this report"
Then I click on "Add audience 'Manually added users'" "link"
And I set the field "Add users manually" to "User 1"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
And I log out
And I log in as "user1"
And I navigate to "Reports > Report builder > Custom reports" in site administration
......@@ -199,7 +201,8 @@ Feature: Configure access to reports based on intended audience
And I should see "Add an audience to this report"
Then I click on "Add audience 'Manually added users'" "link"
And I set the field "Add users manually" to "User 1"
And I press "Save changes"
# It would be better to reference the report table directly, but we can't because of MDL-73011.
And I click on "Save changes" "button" in the "[role=tabpanel].active" "css_element"
And I log out
And I log in as "user1"
And I navigate to "Reports > Report builder > Custom reports" in site administration
......
Supports Markdown
0% or .