Skip to content

Commit

Permalink
MDL-75335 mod_data: Zero state for Fields and Templates
Browse files Browse the repository at this point in the history
  • Loading branch information
Amaia Anabitarte committed Oct 25, 2022
1 parent 32c8f75 commit ab97d41
Show file tree
Hide file tree
Showing 25 changed files with 271 additions and 125 deletions.
13 changes: 13 additions & 0 deletions lib/outputcomponents.php
Expand Up @@ -4569,6 +4569,19 @@ public function set_nowrap_on_items($value = true) {
}
}

/**
* Add classes to the action menu for an easier styling.
*
* @param string $class The class to add to attributes.
*/
public function set_additional_classes(string $class = '') {
if (!empty($this->attributes['class'])) {
$this->attributes['class'] .= " ".$class;
} else {
$this->attributes['class'] = $class;
}
}

/**
* Export for template.
*
Expand Down
4 changes: 1 addition & 3 deletions lib/upgrade.txt
Expand Up @@ -12,9 +12,6 @@ Declaration is as follow:
* coursemodinfo cache uses the new `requirelockingbeforewrite` option, and rebuilding the cache now uses the cache lock API, rather
than using the core lock factory directly. This allows the locks to be stored locally if the cache is stored locally, and
avoids the risk of delays and timeouts when multiple nodes need to rebuild the cache locally, but are waiting for a central lock.

=== 4.1 ===

* Final deprecation and removal of the class \admin_setting_managelicenses, please use \tool_licensemanager\manager instead.
* Final deprecation and removal of the function license_manager::add(). Please use license_manager::save() instead.
* Final deprecation of the following functions behat_field_manager::get_node_type() and behat_field_manager::get_field()
Expand Down Expand Up @@ -60,6 +57,7 @@ Declaration is as follow:
* The function get_module_metadata() has been finally deprecated and can not be used anymore.
* New DML driver method `$DB->sql_order_by_null` for sorting nulls sort nulls first when ascending and last when descending.
* Allow plugins to callback on all pages just prior to the session start.
* New function set_additional_classes() has been implemented to add additional classes to action_menu.

=== 4.0 ===

Expand Down
13 changes: 13 additions & 0 deletions mod/data/classes/manager.php
Expand Up @@ -301,6 +301,19 @@ public function get_template(string $templatename, array $options = []): templat
return new template($this, $templatecontent, $options);
}

/** Check if the user can manage templates on the current context.
*
* @param int $userid the user id to check ($USER->id if null).
* @return bool if the user can manage templates on current context.
*/
public function can_manage_templates(?int $userid = null): bool {
global $USER;
if (!$userid) {
$userid = $USER->id;
}
return has_capability('mod/data:managetemplates', $this->context, $userid);
}

/**
* Update the database templates.
*
Expand Down
56 changes: 39 additions & 17 deletions mod/data/classes/output/action_bar.php
Expand Up @@ -54,8 +54,11 @@ public function __construct(int $id, moodle_url $pageurl) {
* @param bool $hasexportpreset Whether the export as preset button element should be rendered.
* @return string The HTML code for the action bar.
*/
public function get_fields_action_bar(bool $hasfieldselect = false, bool $hassaveaspreset = false,
bool $hasexportpreset = false): string {
public function get_fields_action_bar(
bool $hasfieldselect = false,
bool $hassaveaspreset = false,
bool $hasexportpreset = false
): string {
global $PAGE, $DB;

$createfieldlink = new moodle_url('/mod/data/field.php', ['d' => $this->id]);
Expand All @@ -70,19 +73,7 @@ public function get_fields_action_bar(bool $hasfieldselect = false, bool $hassav

$fieldselect = null;
if ($hasfieldselect) {
// Get the list of possible fields (plugins).
$plugins = \core_component::get_plugin_list('datafield');
$menufield = [];

foreach ($plugins as $plugin => $fulldir) {
$menufield[$plugin] = get_string('pluginname', "datafield_{$plugin}");
}
asort($menufield);

$fieldselecturl = new moodle_url('/mod/data/field.php', ['d' => $this->id, 'mode' => 'new']);
$fieldselect = new \single_select($fieldselecturl, 'newtype', $menufield, null, get_string('newfield', 'data'),
'fieldform');
$fieldselect->set_label(get_string('newfield', 'mod_data'), ['class' => 'sr-only']);
$fieldselect = $this->get_create_fields();
}

$saveaspresetbutton = null;
Expand All @@ -105,12 +96,43 @@ public function get_fields_action_bar(bool $hasfieldselect = false, bool $hassav
}
}
$renderer = $PAGE->get_renderer('mod_data');
$fieldsactionbar = new fields_action_bar($this->id, $urlselect, $fieldselect, $saveaspresetbutton,
$exportpresetbutton);
$fieldsactionbar = new fields_action_bar($this->id, $urlselect, null, $saveaspresetbutton,
$exportpresetbutton, $fieldselect);

return $renderer->render_fields_action_bar($fieldsactionbar);
}

/**
* Generate the output for the create a new field action menu.
*
* @return \action_menu Action menu to create a new field
*/
public function get_create_fields(): \action_menu {
// Get the list of possible fields (plugins).
$plugins = \core_component::get_plugin_list('datafield');
$menufield = [];
foreach ($plugins as $plugin => $fulldir) {
$menufield[$plugin] = get_string('pluginname', "datafield_{$plugin}");
}
asort($menufield);

$fieldselect = new \action_menu();
$fieldselect->set_menu_trigger(get_string('newfield', 'mod_data'), 'btn btn-secondary');
$fieldselectparams = ['d' => $this->id, 'mode' => 'new'];
foreach ($menufield as $fieldtype => $fieldname) {
$fieldselectparams['newtype'] = $fieldtype;
$fieldselect->add(new \action_menu_link(
new \moodle_url('/mod/data/field.php', $fieldselectparams),
new \pix_icon('field/' . $fieldtype, $fieldname, 'data'),
$fieldname,
false
));
}
$fieldselect->set_additional_classes('singlebutton');

return $fieldselect;
}

/**
* Generate the output for the action selector in the view page.
*
Expand Down
13 changes: 10 additions & 3 deletions mod/data/classes/output/fields_action_bar.php
Expand Up @@ -48,12 +48,19 @@ class fields_action_bar implements templatable, renderable {
*
* @param int $id The database module id
* @param \url_select $urlselect The URL selector object
* @param \single_select|null $fieldselect The field selector object or null
* @param null $unused This parameter has been deprecated since 4.0 and should not be used anymore.
* @param \single_button|null $saveaspresetbutton The save as preset single button object or null
* @param \single_button|null $exportpresetbutton The export preset single button object or null
* @param \action_menu|null $fieldselect The field selector object or null
*/
public function __construct(int $id, \url_select $urlselect, ?\single_select $fieldselect = null,
?\single_button $saveaspresetbutton = null, ?\single_button $exportpresetbutton = null) {
public function __construct(int $id, \url_select $urlselect, $unused = null,
?\single_button $saveaspresetbutton = null, ?\single_button $exportpresetbutton = null,
?\action_menu $fieldselect = null) {

if ($unused !== null) {
debugging('Deprecated argument passed to fields_action_bar constructor', DEBUG_DEVELOPER);
}

$this->id = $id;
$this->urlselect = $urlselect;
$this->fieldselect = $fieldselect;
Expand Down
7 changes: 3 additions & 4 deletions mod/data/classes/output/zero_state_action_bar.php
Expand Up @@ -52,7 +52,7 @@ public function export_for_template(\renderer_base $output): array {
global $PAGE;

$data = [];
if (has_capability('mod/data:managetemplates', $PAGE->context)) {
if ($this->manager->can_manage_templates()) {
$instance = $this->manager->get_instance();
$params = ['d' => $instance->id, 'backto' => $PAGE->url->out(false)];

Expand All @@ -61,9 +61,8 @@ public function export_for_template(\renderer_base $output): array {
get_string('usepreset', 'mod_data'), 'get', true);
$data['usepresetbutton'] = $usepresetbutton->export_for_template($output);

$createfieldlink = new moodle_url('/mod/data/field.php', $params);
$createfieldbutton = new \single_button($createfieldlink,
get_string('newfield', 'mod_data'), 'get', false);
$actionbar = new \mod_data\output\action_bar($instance->id, $PAGE->url);
$createfieldbutton = $actionbar->get_create_fields();
$data['createfieldbutton'] = $createfieldbutton->export_for_template($output);

$params['action'] = 'import';
Expand Down
2 changes: 1 addition & 1 deletion mod/data/edit.php
Expand Up @@ -74,7 +74,7 @@
}

/// Can't use this if there are no fields
if (has_capability('mod/data:managetemplates', $context)) {
if ($manager->can_manage_templates()) {
if (!$manager->has_fields()) {
redirect($CFG->wwwroot.'/mod/data/field.php?d='.$data->id); // Redirect to field entry.
}
Expand Down
128 changes: 66 additions & 62 deletions mod/data/field.php
Expand Up @@ -333,75 +333,79 @@
$field->display_edit_field();

} else { /// Display the main listing of all fields
$hasfields = $manager->has_fields();

// Check if it is an empty database with no fields.
if (!$hasfields) {
$PAGE->set_title($data->name);
echo $OUTPUT->header();
echo $renderer->render_fields_zero_state($manager);
echo $OUTPUT->footer();
// Don't check the rest of the options. There is no field, there is nothing else to work with.
exit;
}
$fieldactionbar = $actionbar->get_fields_action_bar(true, true, true);
data_print_header($course, $cm, $data, 'fields', $fieldactionbar);
echo $OUTPUT->heading(get_string('managefields', 'data'), 2, 'mb-4');

if (!$DB->record_exists('data_fields', array('dataid'=>$data->id))) {
echo $OUTPUT->notification(get_string('nofieldindatabase','data')); // nothing in database
echo $OUTPUT->notification(get_string('pleaseaddsome','data', 'preset.php?id='.$cm->id)); // link to presets

} else { //else print quiz style list of fields

$table = new html_table();
$table->head = array(
get_string('fieldname', 'data'),
get_string('type', 'data'),
get_string('required', 'data'),
get_string('fielddescription', 'data'),
get_string('action', 'data'),
);
$table->align = array('left', 'left', 'left', 'left');
$table->wrap = array(false,false,false,false);

if ($fff = $DB->get_records('data_fields', array('dataid'=>$data->id),'id')){
$missingfieldtypes = [];
foreach ($fff as $ff) {

$field = data_get_field($ff, $data);

$baseurl = new moodle_url('/mod/data/field.php', array(
'd' => $data->id,
'fid' => $field->field->id,
'sesskey' => sesskey(),
));

$displayurl = new moodle_url($baseurl, array(
'mode' => 'display',
));

$deleteurl = new moodle_url($baseurl, array(
'mode' => 'delete',
));

// It display a notification when the field type does not exist.
$deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
$editlink = html_writer::link($displayurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
if ($field->type === 'unknown') {
$missingfieldtypes[] = $field->field->name;
$fieldnamedata = $field->field->name;
$fieltypedata = $field->field->type;
$fieldlinkdata = $deletelink;
} else {
$fieldnamedata = html_writer::link($displayurl, $field->field->name);
$fieltypedata = $field->image() . ' ' . $field->name();
$fieldlinkdata = $editlink . ' ' . $deletelink;
}
$table = new html_table();
$table->head = [
get_string('fieldname', 'data'),
get_string('type', 'data'),
get_string('required', 'data'),
get_string('fielddescription', 'data'),
get_string('action', 'data'),
];
$table->align = ['left', 'left', 'left', 'left'];
$table->wrap = [false,false,false,false];

$fieldrecords = $manager->get_field_records();
$missingfieldtypes = [];
foreach ($fieldrecords as $fieldrecord) {

$field = data_get_field($fieldrecord, $data);

$baseurl = new moodle_url('/mod/data/field.php', array(
'd' => $data->id,
'fid' => $field->field->id,
'sesskey' => sesskey(),
));

$displayurl = new moodle_url($baseurl, array(
'mode' => 'display',
));

$deleteurl = new moodle_url($baseurl, array(
'mode' => 'delete',
));

// It display a notification when the field type does not exist.
$deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
$editlink = html_writer::link($displayurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
if ($field->type === 'unknown') {
$missingfieldtypes[] = $field->field->name;
$fieldnamedata = $field->field->name;
$fieltypedata = $field->field->type;
$fieldlinkdata = $deletelink;
} else {
$fieldnamedata = html_writer::link($displayurl, $field->field->name);
$fieltypedata = $field->image() . ' ' . $field->name();
$fieldlinkdata = $editlink . ' ' . $deletelink;
}

$table->data[] = [
$fieldnamedata,
$fieltypedata,
$field->field->required ? get_string('yes') : get_string('no'),
shorten_text($field->field->description, 30),
$fieldlinkdata
];
}
if (!empty($missingfieldtypes)) {
echo $OUTPUT->notification(get_string('missingfieldtypes', 'data') . html_writer::alist($missingfieldtypes));
}
$table->data[] = [
$fieldnamedata,
$fieltypedata,
$field->field->required ? get_string('yes') : get_string('no'),
shorten_text($field->field->description, 30),
$fieldlinkdata
];

if (!empty($missingfieldtypes)) {
echo $OUTPUT->notification(get_string('missingfieldtypes', 'data') . html_writer::alist($missingfieldtypes));
}
echo html_writer::table($table);
}
echo html_writer::table($table);

echo '<div class="sortdefault">';
echo '<form id="sortdefault" action="'.$CFG->wwwroot.'/mod/data/field.php" method="get">';
Expand Down
11 changes: 8 additions & 3 deletions mod/data/lang/en/data.php
Expand Up @@ -78,7 +78,9 @@
$string['confirmdeletefield'] = 'You are about to delete this field, are you sure?';
$string['confirmdeleterecord'] = 'Are you sure you want to delete this entry?';
$string['confirmdeleterecords'] = 'Are you sure you want to delete these entries?';
$string['createfields'] = 'Create your own fields to collect data, or use a preset which includes fields already.';
$string['createactivity'] = 'Create your own fields to collect data, or use a preset which includes fields already.';
$string['createfields'] = 'Create fields to collect different types of data.';
$string['createtemplates'] = 'Create fields for your activity to generate a template, or import a preset with existing fields and templates.';
$string['csstemplate'] = 'CSS template';
$string['csvfailed'] = 'Unable to read the raw data from the CSV file';
$string['csvfile'] = 'CSV file';
Expand Down Expand Up @@ -291,21 +293,24 @@
$string['multimenu'] = 'Menu (Multi-select)';
$string['multipletags'] = 'Multiple tags found! Template not saved';
$string['newentry'] = 'New entry';
$string['newfield'] = 'Create a new field';
$string['newfield'] = 'Create a field';
$string['newfield_help'] = 'A field allows the input of data. Each entry in a database activity can have multiple fields of multiple types such as a date field, which allows participants to select a day, month and year from a drop-down menu, a picture field, which allows participants to upload an image file, or a checkbox field, which allows participants to select one or more options.
Each field must have a unique field name. The field description is optional.';
$string['noaccess'] = 'You do not have access to this page';
$string['nodefinedfields'] = 'New preset has no defined fields!';
$string['nofieldcontent'] = 'Field content not found';
$string['nofieldindatabase'] = 'There are no fields defined for this database.';
$string['nofields'] = 'No fields yet';
$string['nolisttemplate'] = 'List template is not yet defined';
$string['nomatch'] = 'No matching entries found!';
$string['nomaximum'] = 'No maximum';
$string['nopreviewavailable'] = 'No preview available for {$a}';
$string['norecords'] = 'No entries yet';
$string['notapproved'] = 'Pending approval';
$string['notapprovederror'] = 'Entry is not approved yet.';
$string['notinjectivemap'] = 'Not an injective map';
$string['notemplates'] = 'Not templates yet';
$string['notopenyet'] = 'Sorry, this activity is not available until {$a}';
$string['number'] = 'Number';
$string['numberrssarticles'] = 'Entries in the RSS feed';
Expand All @@ -323,7 +328,6 @@
$string['pagesize'] = 'Entries per page';
$string['participants'] = 'Participants';
$string['picture'] = 'Picture';
$string['pleaseaddsome'] = 'Please create some below or <a href="{$a}">choose a predefined set</a> to get started.';
$string['pluginadministration'] = 'Database activity administration';
$string['pluginname'] = 'Database';
$string['portfolionotfile'] = 'Export to a portfolio rather than a file (csv and leap2a only)';
Expand Down Expand Up @@ -455,6 +459,7 @@
$string['buttons'] = 'Actions';
$string['nolisttemplate'] = 'List template is not yet defined';
$string['nosingletemplate'] = 'Single template is not yet defined';
$string['pleaseaddsome'] = 'Please create some below or <a href="{$a}">choose a predefined set</a> to get started.';
$string['blank'] = 'Blank';
$string['savetemplate'] = 'Save template';
$string['addedby'] = 'Added by';
1 change: 1 addition & 0 deletions mod/data/lang/en/deprecated.txt
Expand Up @@ -2,6 +2,7 @@ unsupportedexport,mod_data
buttons,mod_data
nosingletemplate,mod_data
nolisttemplate,mod_data
pleaseaddsome,mod_data
blank,mod_data
savetemplate,mod_data
addedby,mod_data

0 comments on commit ab97d41

Please sign in to comment.