use File::Spec ();
 
-use SL::ClientJS;
 use SL::Common ();
 use SL::Controller::Helper::GetModels;
 use SL::Controller::Helper::ReportGenerator;
 use Rose::Object::MakeMethods::Generic
 (
   scalar                  => [ qw(requirement_spec_item visible_item visible_section) ],
-  'scalar --get_set_init' => [ qw(requirement_spec customers types statuses complexities risks projects project_types project_statuses default_project_type default_project_status copy_source js
+  'scalar --get_set_init' => [ qw(requirement_spec customers types statuses complexities risks projects project_types project_statuses default_project_type default_project_status copy_source
                                   current_text_block_output_position models time_based_units html_template cvar_configs includeable_cvar_configs include_cvars) ],
 );
 
 sub action_list {
   my ($self) = @_;
 
+  $self->_setup_search_action_bar;
   $self->prepare_report;
-  $self->report_generator_list_objects(report => $self->{report}, objects => $self->models->get);
+  $self->report_generator_list_objects(report => $self->{report}, objects => $self->models->get, action_bar => 1);
 }
 
 sub action_new {
     $self->requirement_spec->$_($self->copy_source->$_) for qw(type_id status_id customer_id title hourly_rate is_template)
   }
 
+  $self->_setup_form_action_bar;
+
   $self->render('requirement_spec/new', title => $self->requirement_spec->is_template ? t8('Create a new requirement spec template') : t8('Create a new requirement spec'));
 }
 
   $self->js
     ->hide('#basic_settings')
     ->after('#basic_settings', $html)
-    ->render($self);
+    ->render;
 }
 
 sub action_ajax_edit_project_link {
   $self->js
     ->hide('#basic_settings')
     ->after('#basic_settings', $html)
-    ->render($self);
+    ->render;
 }
 
 sub action_ajax_show_time_and_cost_estimate {
    ->after('#time_cost_estimate', $html)
    ->on('#time_cost_estimate INPUT[type=text]', 'keydown', 'kivi.requirement_spec.time_cost_estimate_input_key_down')
    ->action_if($first && $first->id, 'focus', '#time_and_cost_estimate_form_complexity_id_' . $first->id)
-   ->render($self);
+   ->render;
 }
 
 sub action_ajax_save_time_and_cost_estimate {
   my ($self) = @_;
 
-  $self->requirement_spec->db->do_transaction(sub {
+  $self->requirement_spec->db->with_transaction(sub {
     # Make Emacs happy
     1;
     foreach my $attributes (@{ $::form->{requirement_spec_items} || [] }) {
   my $html = $self->render('requirement_spec/_show_time_and_cost_estimate', { output => 0 }, initially_hidden => !!$::form->{keep_open});
   $self->js->replaceWith('#time_cost_estimate', $html);
 
-  return $self->js->render($self) if $::form->{keep_open};
+  return $self->js->render if $::form->{keep_open};
 
   $self->js->remove('#time_cost_estimate_form_container');
 
     $self->js->html('#column-content', $html);
   }
 
-  $self->js->render($self);
+  $self->js->render;
 }
 
 sub action_show {
 sub action_revert_to {
   my ($self, %params) = @_;
 
-  return $self->js->error(t8('Cannot revert a versioned copy.'))->render($self) if $self->requirement_spec->working_copy_id;
+  return $self->js->error(t8('Cannot revert a versioned copy.'))->render if $self->requirement_spec->working_copy_id;
 
   my $versioned_copy = SL::DB::RequirementSpec->new(id => $::form->{versioned_copy_id})->load;
 
   $version->update_attributes(working_copy_id => $self->requirement_spec->id);
 
   flash_later('info', t8('The requirement spec has been reverted to version #1.', $versioned_copy->version->version_number));
-  $self->js->redirect_to($self->url_for(action => 'show', id => $self->requirement_spec->id))->render($self);
+  $self->js->redirect_to($self->url_for(action => 'show', id => $self->requirement_spec->id))->render;
 }
 
 sub action_create_pdf {
   my $template = SL::DB::RequirementSpec->new(id => $::form->{template_id})->load;
   my %result   = $self->requirement_spec->paste_template($template);
 
-  return $self->js->error($self->requirement_spec->error)->render($self) if !%result;
+  return $self->js->error($self->requirement_spec->error)->render if !%result;
 
   $self->render_pasted_text_block($_) for sort { $a->position <=> $b->position } @{ $result{text_blocks} };
   $self->render_pasted_section($_)    for sort { $a->position <=> $b->position } @{ $result{sections}    };
     ->show(       '#additional_parts_list_container')
     ->remove(     '#additional_parts_form_container');
 
-  $self->invalidate_version->render($self);
+  $self->invalidate_version->render;
 }
 
 sub action_renumber_sections {
 
   $::auth->assert('requirement_spec_edit');
   $::request->{layout}->use_stylesheet("${_}.css") for qw(jquery.contextMenu requirement_spec);
-  $::request->{layout}->use_javascript("${_}.js")  for qw(jquery.jstree jquery/jquery.contextMenu jquery/jquery.hotkeys requirement_spec ckeditor/ckeditor ckeditor/adapters/jquery autocomplete_part autocomplete_customer);
+  $::request->{layout}->use_javascript("${_}.js")  for qw(jquery.jstree jquery/jquery.contextMenu jquery/jquery.hotkeys requirement_spec ckeditor/ckeditor ckeditor/adapters/jquery kivi.Part.js autocomplete_customer);
   $self->init_visible_section;
 
   return 1;
 }
 
-sub init_js                     { SL::ClientJS->new                                           }
 sub init_complexities           { SL::DB::Manager::RequirementSpecComplexity->get_all_sorted  }
 sub init_default_project_status { SL::DB::Manager::ProjectStatus->find_by(name => 'planning') }
 sub init_default_project_type   { SL::DB::ProjectType->new(id => 1)->load                     }
   my @errors = $self->requirement_spec->validate;
 
   if (@errors) {
-    return $self->js->error(@errors)->render($self) if $::request->is_ajax;
+    return $self->js->error(@errors)->render if $::request->is_ajax;
 
     flash('error', @errors);
     $self->render('requirement_spec/new', title => $title);
   }
 
   my $db = $self->requirement_spec->db;
-  if (!$db->do_transaction(sub {
+  if (!$db->with_transaction(sub {
     if ($self->copy_source) {
       $self->requirement_spec($self->copy_source->create_copy(%{ $params }));
     } else {
       $self->requirement_spec->save(cascade => 1);
     }
+    1;
   })) {
     $::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error);
     @errors = ($::locale->text('Saving failed. Error message from the database: #1', $db->error));
-    return $self->js->error(@errors)->render($self) if $::request->is_ajax;
+    return $self->js->error(@errors)->render if $::request->is_ajax;
 
     $self->requirement_spec->id(undef) if $is_new;
     flash('error', @errors);
       ->replaceWith('#basic_settings',          $basics_html)
       ->remove('#basic_settings_form')
       ->flash('info', $info)
-      ->render($self);
+      ->render;
   }
 
   flash_later('info', $info);
     ->replaceWith('#basic_settings', $self->render('requirement_spec/_show_basic_settings', { output => 0 }))
     ->remove('#project_link_form')
     ->flash('info', t8('The project link has been updated.'))
-    ->render($self);
+    ->render;
 }
 
 sub update_project_link_new {
 
   return $self->js
     ->replaceWith('#project_link_form', $self->render('requirement_spec/_new_project_form', { output => 0 }))
-    ->render($self);
+    ->render;
 }
 
 sub update_project_link_create {
 
   my @errors = $project->validate;
 
-  return $self->js->error(@errors)->render($self) if @errors;
+  return $self->js->error(@errors)->render if @errors;
 
   my $db = $self->requirement_spec->db;
-  if (!$db->do_transaction(sub {
+  if (!$db->with_transaction(sub {
     $project->save;
     $self->requirement_spec->update_attributes(project_id => $project->id);
 
   })) {
     $::lxdebug->message(LXDebug::WARN(), "Error: " . $db->error);
-    return $self->js->error(t8('Saving failed. Error message from the database: #1', $db->error))->render($self);
+    return $self->js->error(t8('Saving failed. Error message from the database: #1', $db->error))->render;
   }
 
   return $self->invalidate_version
     ->remove('#project_link_form')
     ->flash('info', t8('The project has been created.'))
     ->flash('info', t8('The project link has been updated.'))
-    ->render($self);
+    ->render;
 }
 
 sub init_models {
   return !!$template;
 }
 
+sub _setup_form_action_bar {
+  my ($self) = @_;
+
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      action => [
+        t8('Save'),
+        submit    => [ '#basic_settings_form', { action => 'RequirementSpec/' . ($self->requirement_spec->id ? 'update' : 'create') } ],
+        accesskey => 'enter',
+      ],
+
+      link => [
+        t8('Abort'),
+        link => $self->url_for(action => 'list', is_template => $self->requirement_spec->is_template),
+      ],
+    );
+  }
+}
+
+sub _setup_search_action_bar {
+  my ($self, %params) = @_;
+
+  for my $bar ($::request->layout->get('actionbar')) {
+    $bar->add(
+      action => [
+        t8('Search'),
+        submit    => [ '#search_form', { action => 'RequirementSpec/list' } ],
+        accesskey => 'enter',
+      ],
+      link => [
+        t8('Add'),
+        link => $self->url_for(action => 'new', is_template => $::form->{is_template}),
+      ],
+    );
+  }
+}
+
 1;