backup MDL-22142 Several changes to the backup UI and it's classes as noted below

*  backup moodleforms for specific stages are now cached between stage processing and display making it possible to leave all validation up to the bridge.
    * The backup stage now relies entirely on the backup controllers save, load, and check methods + dependency checks rather then previous stage processing to ensure accuracy.
    * filename is now a required field and validated to ensure it ends with .zip and is a valid filename.
    * There is now a previous button for backup stages after the initial and before the complete.
    * The progress bar previous stages are now links as well allowing the user to jump to previous stages (not linked on complete of course).
    * The root settings are only shown on the schema stage now if they were changed because of dependency.
    * Stages are now numbered in the progress bar.
    * The complete page now shows a notice that the backup was complete and provides a continue button to view the backup file.
    * Adds administration blocks to the backup pages.
This commit is contained in:
Sam Hemelryk 2010-05-10 02:53:31 +00:00
parent 3987461ab3
commit 4886029cba
7 changed files with 264 additions and 246 deletions

View File

@ -36,6 +36,7 @@ if ($cmid !== null) {
$url->param('cm', $cmid);
}
$PAGE->set_url($url);
$PAGE->set_pagelayout('admin');
$id = $courseid;
$cm = null;
@ -90,7 +91,6 @@ if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
$PAGE->set_title($heading.': '.$backup->get_stage_name());
$PAGE->set_heading($heading);
$PAGE->set_pagelayout('admin');
$PAGE->navbar->add($backup->get_stage_name());
$renderer = $PAGE->get_renderer('core','backup');

View File

@ -49,7 +49,7 @@ class backup_root_task extends backup_task {
// Define filename setting
$filename = new backup_filename_setting('filename', base_setting::IS_FILENAME, 'backup.zip');
$filename->set_ui(get_string('filename', 'backup'), '', array('size'=>50));
$filename->set_ui(get_string('filename', 'backup'), 'backup.zip', array('size'=>50));
$this->add_setting($filename);
// Define users setting (keeping it on hand to define dependencies)

View File

@ -76,7 +76,7 @@ abstract class backup_moodleform extends moodleform {
*/
function definition() {
$mform = $this->_form;
$stage = $mform->addElement('hidden', 'stage', $this->uistage->get_next_stage());
$stage = $mform->addElement('hidden', 'stage', $this->uistage->get_stage());
$stage = $mform->addElement('hidden', 'backup', $this->uistage->get_backupid());
}
/**
@ -84,8 +84,15 @@ abstract class backup_moodleform extends moodleform {
* to add elements on the fly.
*/
function definition_after_data() {
$mform = $this->_form;
$this->add_action_buttons(get_string('cancel'), get_string('onstage'.$this->uistage->get_stage().'action', 'backup'));
$buttonarray=array();
if ($this->uistage->get_stage() > backup_ui::STAGE_INITIAL) {
$buttonarray[] = $this->_form->createElement('submit', 'previous', get_string('previousstage','backup'));
}
$buttonarray[] = $this->_form->createElement('submit', 'submitbutton', get_string('onstage'.$this->uistage->get_stage().'action', 'backup'));
$buttonarray[] = $this->_form->createElement('cancel');
$this->_form->addGroup($buttonarray, 'buttonar', '', array(' '), false);
$this->_form->closeHeaderBefore('buttonar');
}
/**
* Closes any open divs
@ -257,4 +264,26 @@ class backup_schema_form extends backup_moodleform {}
* Nothing to override we only need it defined so that moodleform doesn't get confused
* between stages.
*/
class backup_confirmation_form extends backup_moodleform {}
class backup_confirmation_form extends backup_moodleform {
public function definition_after_data() {
parent::definition_after_data();
$this->_form->addRule('setting_root_filename', get_string('errorfilenamerequired', 'backup'), 'required');
$this->_form->setType('setting_root_filename', PARAM_FILE);
}
public function validation($data, $files) {
$errors = parent::validation($data, $files);
if (!array_key_exists('setting_root_filename', $errors)) {
if (trim($data['setting_root_filename']) == '') {
$errors['setting_root_filename'] = get_string('errorfilenamerequired', 'backup');
} else if (!preg_match('#\.zip$#i', $data['setting_root_filename'])) {
$errors['setting_root_filename'] = get_string('errorfilenamemustbezip', 'backup');
}
}
return $errors;
}
}

View File

@ -40,6 +40,7 @@ class backup_ui {
const STAGE_SCHEMA = 2;
const STAGE_CONFIRMATION = 4;
const STAGE_FINAL = 8;
const STAGE_COMPLETE = 16;
/**
* The progress of this instance of the backup ui class
*/
@ -109,55 +110,6 @@ class backup_ui {
}
return $stage;
}
/**
* This passes off processing for the current stage to the previous stage.
*
* This occurs when the current stage hasn't been completed yet
*
* @param backup_ui_stage $stage
* @return bool
*/
public function process_previous_stage(backup_ui_stage $stage) {
$prevstage = $stage->get_prev_stage();
if ($prevstage) {
$prevstage = $this->initialise_stage($prevstage);
if ($prevstage) {
return $prevstage->process();
}
}
return false;
}
/**
* This magical function processes all previous stages to the provided stage
* given its backup_moodleform
*
* @param backup_ui_stage $stage
* @param backup_moodleform $form
* @return int The number of changes made by the user
*/
public function process_all_previous_stages(backup_ui_stage $stage, backup_moodleform $form) {
$stages = array();
// First get an instance of each previous stage
while ($stage instanceof backup_ui_stage) {
$stage = $stage->get_prev_stage();
if ($stage) {
$stage = $this->initialise_stage($stage);
$stages[] = $stage;
}
}
$stages = array_reverse($stages);
$changes = 0;
// The process each stage in the correct order.
foreach ($stages as $stage) {
$outcome = $stage->process($form);
// Check it didn't fail
if ($outcome === false) {
throw new backup_ui_exception('backup_ui_process_all_previous_stages_failed', $stage->get_stage());
}
$changes += $outcome;
}
return $changes;
}
/**
* This processes the current stage of the backup
* @return bool
@ -167,8 +119,19 @@ class backup_ui {
throw new backup_ui_exception('backupuialreadyprocessed');
}
$this->progress = self::PROGRESS_PROCESSED;
if (optional_param('previous', false, PARAM_BOOL) && $this->stage->get_stage() > self::STAGE_INITIAL) {
$this->stage = $this->initialise_stage($this->stage->get_prev_stage());
return false;
}
// Process the stage
$processoutcome = $this->stage->process();
if ($processoutcome !== false) {
$this->stage = $this->initialise_stage($this->stage->get_next_stage());
}
// Process UI event after to check changes are valid
$this->controller->process_ui_event();
return $processoutcome;
@ -325,7 +288,9 @@ class backup_ui {
* @return array Array of items for the progress bar
*/
public function get_progress_bar() {
$stage = self::STAGE_FINAL;
global $PAGE;
$stage = self::STAGE_COMPLETE;
$currentstage = $this->stage->get_stage();
$items = array();
while ($stage > 0) {
@ -337,10 +302,11 @@ class backup_ui {
} else if ($stage < $currentstage) {
$classes[] = 'backup_stage_complete';
}
array_unshift($items, array(
'text' => get_string('currentstage'.$stage, 'backup'),
'class' => join(' ', $classes)
));
$item = array('text' => strlen(decbin($stage)).'. '.get_string('currentstage'.$stage, 'backup'),'class' => join(' ', $classes));
if ($stage < $currentstage && $currentstage < self::STAGE_COMPLETE) {
$item['link'] = new moodle_url($PAGE->url, array('backup'=>$this->get_backupid(), 'stage'=>$stage));
}
array_unshift($items, $item);
$stage = floor($stage/2);
}
return $items;
@ -366,6 +332,19 @@ class backup_ui {
public function get_controller_id() {
return $this->controller->get_id();
}
/**
* Gets the requested setting
* @param string $name
* @return mixed
*/
public function get_setting($name, $default = false) {
try {
return $this->controller->get_plan()->get_setting($name);
} catch (Exception $e) {
debugging('Failed to find the setting: '.$name, DEBUG_DEVELOPER);
return $default;
}
}
/**
* Gets the value for the requested setting
*

View File

@ -49,6 +49,11 @@ abstract class backup_ui_stage {
* @var backup_ui
*/
protected $ui;
/**
* The moodleform for this stage
* @var backup_moodleform
*/
protected $stageform = null;
/**
*
* @param backup_ui $ui
@ -139,50 +144,46 @@ class backup_ui_stage_initial extends backup_ui_stage {
$this->stage = backup_ui::STAGE_INITIAL;
parent::__construct($ui);
}
/**
* Processes the initial backup stage
* @param backup_moodleform $form
* @return int The number of changes
*/
public function process(backup_moodleform $form = null) {
// If we wern't given a form create an instance of the form for this stage
if (is_null($form)) {
$form = $this->initialise_stage_form();
// Check it wasn't cancelled
if ($form->is_cancelled()) {
$this->ui->cancel_backup();
}
public function process(backup_moodleform $m = null) {
$form = $this->initialise_stage_form();
if ($form->is_cancelled()) {
$this->ui->cancel_backup();
}
// Check if it was submit
$data = $form->get_data();
if (!$data || !confirm_sesskey()) {
return $this->ui->process_previous_stage($this);
}
// Store the tasks a variable so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
$changes = 0;
foreach ($tasks as &$task) {
// We are only interesting in the backup root task for this stage
if ($task instanceof backup_root_task) {
// Get all settings into a var so we can iterate by reference
$settings = $task->get_settings();
foreach ($settings as &$setting) {
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
} else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
$setting->set_value(0);
$changes++;
if ($data && confirm_sesskey()) {
$tasks = $this->ui->get_backup_tasks();
$changes = 0;
foreach ($tasks as &$task) {
// We are only interesting in the backup root task for this stage
if ($task instanceof backup_root_task) {
// Get all settings into a var so we can iterate by reference
$settings = $task->get_settings();
foreach ($settings as &$setting) {
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
} else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
$setting->set_value(0);
$changes++;
}
}
}
}
// Return the number of changes the user made
return $changes;
} else {
return false;
}
// Return the number of changes the user made
return $changes;
}
/**
@ -192,33 +193,36 @@ class backup_ui_stage_initial extends backup_ui_stage {
*/
protected function initialise_stage_form() {
global $PAGE;
$form = new backup_initial_form($this, $PAGE->url);
// Store as a variable so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
// Iterate all tasks by reference
foreach ($tasks as &$task) {
// For the initial stage we are only interested in the root settings
if ($task instanceof backup_root_task) {
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
$settings = $task->get_settings();
// First add all settings except the filename setting
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
if ($this->stageform === null) {
$form = new backup_initial_form($this, $PAGE->url);
// Store as a variable so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
// Iterate all tasks by reference
foreach ($tasks as &$task) {
// For the initial stage we are only interested in the root settings
if ($task instanceof backup_root_task) {
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
$settings = $task->get_settings();
// First add all settings except the filename setting
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
}
$form->add_setting($setting, $task);
}
$form->add_setting($setting, $task);
}
// Then add all dependencies
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
// Then add all dependencies
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
}
$form->add_dependencies($setting);
}
$form->add_dependencies($setting);
}
}
$this->stageform = $form;
}
// Return the form
return $form;
return $this->stageform;
}
}
@ -247,51 +251,42 @@ class backup_ui_stage_schema extends backup_ui_stage {
* @return int The number of changes the user made
*/
public function process(backup_moodleform $form = null) {
// If we wern't given a form instantiate a new form for this stage
if (is_null($form)) {
$form = $this->initialise_stage_form();
// Check it wasn't cancelled
if ($form->is_cancelled()) {
$this->ui->cancel_backup();
}
$form = $this->initialise_stage_form();
// Check it wasn't cancelled
if ($form->is_cancelled()) {
$this->ui->cancel_backup();
}
// Check it has been submit
$data = $form->get_data();
if (!$data || !confirm_sesskey()) {
return $this->ui->process_previous_stage($this);
}
// If this stage is the current stage first process all other stages
// to ensure we respect dependencies in the correct order.
if ($this->ui->get_stage() == $this->get_next_stage()) {
$this->ui->process_all_previous_stages($this, $form);
}
// Get the tasks into a var so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
$changes = 0;
// Iterate all tasks by reference
foreach ($tasks as &$task) {
// We are only interested in schema settings
if (!($task instanceof backup_root_task)) {
// Store as a variable so we can iterate by reference
$settings = $task->get_settings();
// Iterate by reference
foreach ($settings as &$setting) {
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
} else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
$setting->set_value(0);
$changes++;
if ($data && confirm_sesskey()) {
// Get the tasks into a var so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
$changes = 0;
// Iterate all tasks by reference
foreach ($tasks as &$task) {
// We are only interested in schema settings
if (!($task instanceof backup_root_task)) {
// Store as a variable so we can iterate by reference
$settings = $task->get_settings();
// Iterate by reference
foreach ($settings as &$setting) {
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
} else if (!isset($data->$name) && $setting->get_ui_type() == backup_setting::UI_HTML_CHECKBOX && $setting->get_value()) {
$setting->set_value(0);
$changes++;
}
}
}
}
}
// Return the number of changes the user made
return $changes;
// Return the number of changes the user made
return $changes;
} else {
return false;
}
}
/**
* Creates the backup_schema_form instance for this stage
@ -300,38 +295,42 @@ class backup_ui_stage_schema extends backup_ui_stage {
*/
protected function initialise_stage_form() {
global $PAGE;
$form = new backup_schema_form($this, $PAGE->url);
$tasks = $this->ui->get_backup_tasks();
$content = '';
$courseheading = false;
foreach ($tasks as $task) {
if ($task instanceof backup_root_task) {
// Add a root settings heading to group nicely
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
// Iterate all settings and add them to the form as a fixed
// setting. We only want schema settings to be editable
foreach ($task->get_settings() as $setting) {
if ($setting->get_name() != 'filename') {
$form->add_fixed_setting($setting);
if ($this->stageform === null) {
$form = new backup_schema_form($this, $PAGE->url);
$tasks = $this->ui->get_backup_tasks();
$content = '';
$courseheading = false;
foreach ($tasks as $task) {
if (!($task instanceof backup_root_task)) {
if (!$courseheading) {
// If we havn't already display a course heading to group nicely
$form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
$courseheading = true;
}
// First add each setting
foreach ($task->get_settings() as $setting) {
$form->add_setting($setting, $task);
}
// The add all the dependencies
foreach ($task->get_settings() as $setting) {
$form->add_dependencies($setting);
}
} else if ($this->ui->enforce_changed_dependencies()) {
// Only show these settings if dependencies changed them.
// Add a root settings heading to group nicely
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
// Iterate all settings and add them to the form as a fixed
// setting. We only want schema settings to be editable
foreach ($task->get_settings() as $setting) {
if ($setting->get_name() != 'filename') {
$form->add_fixed_setting($setting);
}
}
}
} else {
if (!$courseheading) {
// If we havn't already display a course heading to group nicely
$form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
$courseheading = true;
}
// First add each setting
foreach ($task->get_settings() as $setting) {
$form->add_setting($setting, $task);
}
// The add all the dependencies
foreach ($task->get_settings() as $setting) {
$form->add_dependencies($setting);
}
}
$this->stageform = $form;
}
return $form;
return $this->stageform;
}
}
@ -360,46 +359,34 @@ class backup_ui_stage_confirmation extends backup_ui_stage {
* @return int The number of changes the user made
*/
public function process(backup_moodleform $form = null) {
// If we don't have a form passed in then we need to initalise the
// form for this stage
if (is_null($form)) {
$form = $this->initialise_stage_form();
// Check it hasn't been cancelled
if ($form->is_cancelled()) {
$this->ui->cancel_backup();
}
$form = $this->initialise_stage_form();
// Check it hasn't been cancelled
if ($form->is_cancelled()) {
$this->ui->cancel_backup();
}
// Get the data (will be false if not submit yet)
$data = $form->get_data();
// If not submit or sesskey incorrect process the previous stage
if (!$data || !confirm_sesskey()) {
return $this->ui->process_previous_stage($this);
}
// If this stage is the current stage first process all other stages
// to ensure we respect dependencies in the correct order.
if ($this->ui->get_stage() == $this->get_stage()) {
$this->ui->process_all_previous_stages($this, $form);
}
// Collect into a variable so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
$changes = 0;
// Iterate each task by reference
foreach ($tasks as &$task) {
if ($task instanceof backup_root_task) {
// At this stage all we are interested in is the filename setting
$setting = $task->get_setting('filename');
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
if ($data && confirm_sesskey()) {
// Collect into a variable so we can iterate by reference
$tasks = $this->ui->get_backup_tasks();
$changes = 0;
// Iterate each task by reference
foreach ($tasks as &$task) {
if ($task instanceof backup_root_task) {
// At this stage all we are interested in is the filename setting
$setting = $task->get_setting('filename');
$name = $setting->get_ui_name();
if (isset($data->$name) && $data->$name != $setting->get_value()) {
$setting->set_value($data->$name);
$changes++;
}
}
}
// Return the number of changes the user made
return $changes;
} else {
return false;
}
// Return the number of changes the user made
return $changes;
}
/**
* Creates the backup_confirmation_form instance this stage requires
@ -408,39 +395,45 @@ class backup_ui_stage_confirmation extends backup_ui_stage {
*/
protected function initialise_stage_form() {
global $PAGE;
// Get the form
$form = new backup_confirmation_form($this, $PAGE->url);
$content = '';
$courseheading = false;
foreach ($this->ui->get_backup_tasks() as $task) {
if ($task instanceof backup_root_task) {
// If its a backup root add a root settings heading to group nicely
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
} else if (!$courseheading) {
// we havn't already add a course heading
$form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
$courseheading = true;
if ($this->stageform === null) {
// Get the form
$form = new backup_confirmation_form($this, $PAGE->url);
$content = '';
$courseheading = false;
if ($setting = $this->ui->get_setting('filename')) {
$form->add_heading('filenamesetting', get_string('filename', 'backup'));
if ($setting->get_value() == 'backup.zip') {
$format = $this->ui->get_backup_format();
$type = $this->ui->get_backup_type();
$id = $this->ui->get_controller_id();
$users = $this->ui->get_setting_value('users');
$anonymised = $this->ui->get_setting_value('anonymize');
$setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
}
$form->add_setting($setting);
}
// Iterate all settings, doesnt need to happen by reference
foreach ($task->get_settings() as $setting) {
// For this stage only the filename setting should be editable
if ($setting->get_name() != 'filename') {
$form->add_fixed_setting($setting);
} else {
$value = $setting->get_value();
if (empty($value)) {
$format = $this->ui->get_backup_format();
$type = $this->ui->get_backup_type();
$id = $this->ui->get_controller_id();
$users = $this->ui->get_setting_value('users');
$anonymised = $this->ui->get_setting_value('anonymize');
$setting->set_value(backup_plan_dbops::get_default_backup_filename($format, $type, $id, $users, $anonymised));
foreach ($this->ui->get_backup_tasks() as $task) {
if ($task instanceof backup_root_task) {
// If its a backup root add a root settings heading to group nicely
$form->add_heading('rootsettings', get_string('rootsettings', 'backup'));
} else if (!$courseheading) {
// we havn't already add a course heading
$form->add_heading('coursesettings', get_string('coursesettings', 'backup'));
$courseheading = true;
}
// Iterate all settings, doesnt need to happen by reference
foreach ($task->get_settings() as $setting) {
// For this stage only the filename setting should be editable
if ($setting->get_name() != 'filename') {
$form->add_fixed_setting($setting);
}
$form->add_setting($setting, $task);
}
}
$this->stageform = $form;
}
return $form;
return $this->stageform;
}
}
@ -477,7 +470,7 @@ class backup_ui_stage_final extends backup_ui_stage {
* In this case it ALWAYS passes processing to the previous stage (confirmation)
*/
public function process(backup_moodleform $form=null) {
return $this->ui->process_previous_stage($this);
return true;
}
/**
* should NEVER be called... throws an exception
@ -516,14 +509,19 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
public function __construct(backup_ui $ui, $results) {
$this->results = $results;
parent::__construct($ui);
$this->stage = backup_ui::STAGE_COMPLETE;
}
/**
* Displays the completed backup stage.
*
* Currently this just envolves redirecting to the file browser with an
* appropriate message.
*
* @global core_renderer $OUTPUT
*/
public function display() {
global $OUTPUT;
// Get the resulting stored_file record
$file = $this->results['backup_destination'];
// Turn it into a url for the file browser
@ -533,7 +531,10 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
'itemid' => $file->get_itemid(),
'filepath' => $file->get_filepath()
));
// Redirect the user with a useful message
redirect($fileurl, get_string('executionsuccess', 'backup'), 3);
echo $OUTPUT->box_start();
echo get_string('executionsuccess', 'backup');
echo $OUTPUT->continue_button($fileurl);
echo $OUTPUT->box_end();
}
}

View File

@ -45,7 +45,13 @@ class core_backup_renderer extends plugin_renderer_base {
foreach ($items as &$item) {
$text = $item['text'];
unset($item['text']);
$item = html_writer::tag('span', $text, $item);
if (array_key_exists('link', $item)) {
$link = $item['link'];
unset($item['link']);
$item = html_writer::link($link, $text, $item);
} else {
$item = html_writer::tag('span', $text, $item);
}
}
return html_writer::tag('div', join(get_separator(), $items), array('class'=>'backup_progress clearfix'));
}

View File

@ -33,7 +33,9 @@ $string['currentstage4'] = 'Confirmation and review';
$string['currentstage8'] = 'Perform backup';
$string['currentstage16'] = 'Complete';
$string['dependenciesenforced'] = 'Your settings have been altered due to unmet dependencies';
$string['executionsuccess'] = 'Your backup completed successfully, you will be redirected momentarily to the backup section for this course.';
$string['errorfilenamerequired'] = 'You must enter a valid filename for this backup';
$string['errorfilenamemustbezip'] = 'The filename you enter must be a ZIP file and have the .zip extension';
$string['executionsuccess'] = 'Your backup completed successfully, clicking the continue button below will take you to view your backup file.';
$string['filename'] = 'Filename';
$string['includesection'] = 'Include section {$a}';
$string['includeother'] = 'Include {$a}';
@ -44,4 +46,5 @@ $string['onstage2action'] = 'Next';
$string['onstage4action'] = 'Perform backup';
$string['onstage8action'] = 'Continue';
$string['onstage16action'] = 'Continue';
$string['previousstage'] = 'Previous';
$string['rootsettings'] = 'Backup settings';